changeset 1184:d201987cb76c

6829144: JSR 292 JVM features need a provisional Java API Summary: JDK API and runtime (partial) for anonk, meth, indy Reviewed-by: mr
author jrose
date Tue, 05 May 2009 22:40:09 -0700
parents b3720710a4ba
children 9ba256e2e5c1
files make/docs/CORE_PKGS.gmk make/java/Makefile make/java/dyn/Makefile src/share/classes/java/dyn/CallSite.java src/share/classes/java/dyn/InvokeDynamic.java src/share/classes/java/dyn/InvokeDynamicBootstrapError.java src/share/classes/java/dyn/JavaMethodHandle.java src/share/classes/java/dyn/Linkage.java src/share/classes/java/dyn/LinkagePermission.java src/share/classes/java/dyn/MethodHandle.java src/share/classes/java/dyn/MethodHandles.java src/share/classes/java/dyn/MethodType.java src/share/classes/java/dyn/MethodTypeForm.java src/share/classes/java/dyn/NoAccessException.java src/share/classes/java/dyn/WrongMethodTypeException.java src/share/classes/java/dyn/package-info.java src/share/classes/sun/dyn/Access.java src/share/classes/sun/dyn/AdapterMethodHandle.java src/share/classes/sun/dyn/BoundMethodHandle.java src/share/classes/sun/dyn/CallSiteImpl.java src/share/classes/sun/dyn/DirectMethodHandle.java src/share/classes/sun/dyn/FilterGeneric.java src/share/classes/sun/dyn/FilterOneArgument.java src/share/classes/sun/dyn/FromGeneric.java src/share/classes/sun/dyn/Invokers.java src/share/classes/sun/dyn/MemberName.java src/share/classes/sun/dyn/MethodHandleImpl.java src/share/classes/sun/dyn/MethodHandleNatives.java src/share/classes/sun/dyn/MethodTypeImpl.java src/share/classes/sun/dyn/ToGeneric.java src/share/classes/sun/dyn/anon/AnonymousClassLoader.java src/share/classes/sun/dyn/anon/ConstantPoolParser.java src/share/classes/sun/dyn/anon/ConstantPoolPatch.java src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java src/share/classes/sun/dyn/empty/Empty.java src/share/classes/sun/dyn/package-info.java src/share/classes/sun/dyn/util/BytecodeName.java src/share/classes/sun/dyn/util/BytecodeSignature.java src/share/classes/sun/dyn/util/ValueConversions.java src/share/classes/sun/dyn/util/VerifyAccess.java src/share/classes/sun/dyn/util/VerifyType.java src/share/classes/sun/dyn/util/Wrapper.java src/share/classes/sun/dyn/util/package-info.java src/share/classes/sun/misc/Unsafe.java src/share/javavm/export/classfile_constants.h src/share/native/common/check_code.c src/share/native/common/opcodes.in_out
diffstat 48 files changed, 11529 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/make/docs/CORE_PKGS.gmk	Mon May 04 22:16:02 2009 -0700
+++ b/make/docs/CORE_PKGS.gmk	Tue May 05 22:40:09 2009 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2001-2009 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2001-2008 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
@@ -55,6 +55,7 @@
 # This is a list of regular expressions. So foo.* matches "foo" and "foo.bar".
 #
 ACTIVE_JSR_PKGS= \
+  java.dyn \
   java.sql  \
   javax.activation  \
   javax.annotation.*  \
--- a/make/java/Makefile	Mon May 04 22:16:02 2009 -0700
+++ b/make/java/Makefile	Tue May 05 22:40:09 2009 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 1995-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
@@ -39,7 +39,7 @@
 # Others
 #    Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk
 SUBDIRS += security npt java_crw_demo java_hprof_demo \
-	    math awt util text applet net nio \
+	    math awt util text applet net nio dyn \
 	    sql rmi jar beans logging management instrument
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/java/dyn/Makefile	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+BUILDDIR = ../..
+
+PACKAGE = java.dyn
+PRODUCT = java
+include $(BUILDDIR)/common/Defs.gmk
+
+AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
+
+# The sources built here use new language syntax to generate
+# method handle calls.  Let's be sure we are using that format.
+#LANGUAGE_VERSION = -source 7
+#CLASS_VERSION = -target 7
+
+# Actually, it will be less disruptive to compile with the same
+# -target option as the rest of the system, and just turn on
+# the specific compiler option we need here:
+OTHER_JAVACFLAGS = -XDinvokedynamic
+
+include $(BUILDDIR)/common/Classes.gmk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/CallSite.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,201 @@
+/*
+ * 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 java.dyn;
+
+import sun.dyn.util.BytecodeName;
+
+/**
+ * An <code>invokedynamic</code> call site, as reified to the bootstrap method.
+ * Every instance of a call site corresponds to a distinct instance
+ * of the <code>invokedynamic</code> instruction.
+ * Call sites have state, one reference word, called the <code>target</code>,
+ * and typed as a {@link MethodHandle}.  When this state is null (as it is
+ * initially) the call site is in the unlinked state.  Otherwise, it is said
+ * to be linked to its target.
+ * <p>
+ * When an unlinked call site is executed, a bootstrap routine is called
+ * to finish the execution of the call site, and optionally to link
+ * the call site.
+ * <p>
+ * @author John Rose, JSR 292 EG
+ */
+public class CallSite {
+    // Fields used only by the JVM.  Do not use or change.
+    private Object vmmethod;
+    int callerMID, callerBCI;  // supplied by the JVM
+
+    MethodHandle target;
+    final Object caller;  // usually a class
+    final String name;
+    final MethodType type;
+
+    public CallSite(Object caller, String name, MethodType type) {
+        this.caller = caller;
+        this.name = name;
+        this.type = type;
+    }
+
+    private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
+        site.callerMID = callerMID;
+        site.callerBCI = callerBCI;
+        if (site.target == null)
+            site.setTarget(site.initialTarget());
+    }
+
+    /**
+     * Just after a call site is created by a bootstrap method handle,
+     * if the target has not been initialized by the factory method itself,
+     * the method {@code initialTarget} is called to produce an initial
+     * non-null target.  (Live call sites must never have null targets.)
+     * <p>
+     * If the bootstrap method itself does not initialize the call site,
+     * this method must be overridden, because it just raises an
+     * {@code InvokeDynamicBootstrapError}.
+     */
+    protected MethodHandle initialTarget() {
+        throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+this);
+    }
+
+    /**
+     * Report the current linkage state of the call site.  (This is mutable.)
+     * The value is null if and only if the call site is currently unlinked.
+     * When a linked call site is invoked, the target method is used directly.
+     * When an unlinked call site is invoked, its bootstrap method receives
+     * the call, as if via {@link Linkage#bootstrapInvokeDynamic}.
+     * <p>
+     * The interactions of {@code getTarget} with memory are the same
+     * as of a read from an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, the current thread may choose to reuse the result
+     * of a previous read of the target from memory, and may fail to see
+     * a recent update to the target by another thread.
+     * @return the current linkage state of the call site
+     * @see #setTarget
+     */
+    public MethodHandle getTarget() {
+        return target;
+    }
+
+    /**
+     * Link or relink the call site, by setting its target method.
+     * <p>
+     * The interactions of {@code setTarget} with memory are the same
+     * as of a write to an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, unrelated threads may fail to see the updated target
+     * until they perform a read from memory.
+     * Stronger guarantees can be created by putting appropriate operations
+     * into the bootstrap method and/or the target methods used
+     * at any given call site.
+     * @param target the new target, or null if it is to be unlinked
+     * @throws WrongMethodTypeException if the new target is not null
+     *         and has a method type that differs from the call site's {@link #type}
+     */
+    public void setTarget(MethodHandle target) {
+        checkTarget(target);
+        this.target = target;
+    }
+
+    protected void checkTarget(MethodHandle target) {
+        if (!canSetTarget(target))
+            throw new WrongMethodTypeException(String.valueOf(target));
+    }
+
+    protected boolean canSetTarget(MethodHandle target) {
+        return (target != null && target.type() == type());
+    }
+
+    /**
+     * Report the class containing the call site.
+     * This is immutable static context.
+     * @return class containing the call site
+     */
+    public Class<?> callerClass() {
+        return (Class) caller;
+    }
+
+    /**
+     * Report the method name specified in the {@code invokedynamic} instruction.
+     * This is immutable static context.
+     * <p>
+     * Note that the name is a JVM bytecode name, and as such can be any
+     * non-empty string, as long as it does not contain certain "dangerous"
+     * characters such as slash {@code '/'} and dot {@code '.'}.
+     * See the Java Virtual Machine specification for more details.
+     * <p>
+     * Application such as a language runtimes may need to encode
+     * arbitrary program element names and other configuration information
+     * into the name.  A standard convention for doing this is
+     * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
+     * @return method name specified by the call site
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Report the method name specified in the {@code invokedynamic} instruction,
+     * as a series of components, individually demangled according to
+     * the standard convention
+     * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
+     * <p>
+     * Non-empty runs of characters between dangerous characters are demangled.
+     * Each component is either a completely arbitrary demangled string,
+     * or else a character constant for a punctuation character, typically ':'.
+     * (In principle, the character can be any dangerous character that the
+     * JVM lets through in a method name, such as '$' or ']'.
+     * Runtime implementors are encouraged to use colon ':' for building
+     * structured names.)
+     * <p>
+     * In the common case where the name contains no dangerous characters,
+     * the result is an array whose only element array is the demangled
+     * name at the call site.  Such a demangled name can be any sequence
+     * of any number of any unicode characters.
+     * @return method name components specified by the call site
+     */
+    public Object[] nameComponents() {
+        return BytecodeName.parseBytecodeName(name);
+    }
+
+    /**
+     * Report the resolved result and parameter types of this call site,
+     * which are derived from its bytecode-level invocation descriptor.
+     * The types are packaged into a {@link MethodType}.
+     * Any linked target of this call site must be exactly this method type.
+     * This is immutable static context.
+     * @return method type specified by the call site
+     */
+    public MethodType type() {
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/InvokeDynamic.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * Syntactic marker interface to request javac to emit an {@code invokedynamic} instruction.
+ * <p>
+ * This type has no particular meaning as a class or interface supertype, and can never be instantiated.
+ * Logically, it denotes a source of all dynamically typed methods.
+ * @author John Rose, JSR 292 EG
+ */
+public final class InvokeDynamic {
+    private InvokeDynamic() { throw new InternalError(); }  // do not instantiate
+
+    // no statically defined static methods
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * Thrown to indicate that an {@code invokedynamic} instruction has
+ * failed to find its bootstrap method, or the bootstrap method has
+ * failed to provide a call site with a non-null target.
+ * <p>
+ * The boostrap method must have been declared during a class's initialization
+ * by a call to {@link Linkage#registerBootstrapMethod}.
+ *
+ * @author John Rose, JSR 292 EG
+ */
+public class InvokeDynamicBootstrapError extends LinkageError {
+    /**
+     * Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
+     */
+    public InvokeDynamicBootstrapError() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code InvokeDynamicBootstrapError} with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public InvokeDynamicBootstrapError(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/JavaMethodHandle.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,83 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * A Java method handle extends the basic method handle type with additional
+ * programmer defined methods and fields.
+ * Its behavior as a method handle is determined at instance creation time,
+ * by providing the new instance with an "entry point" method handle
+ * to handle calls.  This entry point must accept a leading argument
+ * whose type is the Java method handle itself or a supertype, and the
+ * entry point is always called with the Java method handle itself as
+ * the first argument.  This is similar to ordinary virtual methods, which also
+ * accept the receiver object {@code this} as an implicit leading argument.
+ * The {@code MethodType} of the Java method handle is the same as that
+ * of the entry point method handle, with the leading parameter type
+ * omitted.
+ * <p>
+ * Here is an example of usage:
+ * <p><blockquote><pre>
+ *     class Greeter extends JavaMethodHandle {
+ *         public void run() { System.out.println("hello, "+greetee); }
+ *         private final String greetee;
+ *         Greeter(String greetee) {
+ *             super(RUN);
+ *             this.greetee = greetee;
+ *         }
+ *         // the entry point function is computed once:
+ *         private static final MethodHandle RUN
+ *             = MethodHandles.findVirtual(MyMethodHandle.class, "run",
+ *                   MethodType.make(void.class));
+ *     }
+ *     Greeter greeter = new Greeter("world");
+ *     greeter.run();  // prints "hello, world"
+ *     MethodHandle mh = greeter;
+ *     mh.invoke();  // also prints "hello, world"
+ * </pre></blockquote>
+ * <p>
+ * In this example, the method {@code run} provides the entry point.
+ * The entry point need not be a constant value; it may be independently
+ * computed in each call to the constructor.  The entry point does not
+ * even need to be a method on the Java method handle class, though
+ * that is the typical case.
+ * @see MethodHandle
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class JavaMethodHandle
+        // Note: This is an implementation inheritance hack, and will be removed
+        // with a JVM change which moves the required hidden behavior onto this class.
+        extends sun.dyn.BoundMethodHandle
+{
+    /**
+     * When creating a, pass in {@code entryPoint}, any method handle which
+     * can take the current object
+     * @param entryPoint
+     */
+    protected JavaMethodHandle(MethodHandle entryPoint) {
+        super(entryPoint, 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/Linkage.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,199 @@
+/*
+ * 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 java.dyn;
+
+import java.util.WeakHashMap;
+import sun.reflect.Reflection;
+import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
+
+/**
+ * Static methods which control the linkage of invokedynamic call sites.
+ * @author John Rose, JSR 292 EG
+ */
+public class Linkage {
+    private Linkage() {}  // do not instantiate
+
+    /**
+     * Register a bootstrap method for use for a given caller class.
+     * The method handle must be of a type equivalent to {@link Linkage#makeCallSite}.
+     * <p>
+     * The operation will fail with an exception if any of the following conditions hold:
+     * <ul>
+     * <li>The caller of this method is in a different package than the {@code callerClass},
+     *     and there is a security manager, and its {@code checkPermission} call throws
+     *     when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
+     * <li>The given class already has a bootstrap method, either from an embedded
+     *     {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
+     *     call to this method.
+     * <li>The given class is already fully initialized.
+     * <li>The given class is in the process of initialization, in another thread.
+     * </ul>
+     * Because of these rules, a class may install its own bootstrap method in
+     * a static initializer.
+     */
+    public static
+    void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
+        Class callc = Reflection.getCallerClass(2);
+        checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
+        checkBSM(mh);
+        synchronized (bootstrapMethods) {
+            if (bootstrapMethods.containsKey(callerClass))
+                throw new IllegalStateException("bootstrap method already declared in "+callerClass);
+            bootstrapMethods.put(callerClass, mh);
+        }
+    }
+
+    static void checkBSM(MethodHandle mh) {
+        if (mh == null)  throw new IllegalArgumentException("null bootstrap method");
+        if (mh.type() == OLD_BOOTSTRAP_METHOD_TYPE) // FIXME: delete at EDR/PFD
+            throw new WrongMethodTypeException("bootstrap method must be a CallSite factory");
+        if (mh.type() != BOOTSTRAP_METHOD_TYPE)
+            throw new WrongMethodTypeException(mh.toString());
+    }
+
+    /**
+     * Simplified version of registerBootstrapMethod for self-registration,
+     * to be called from a static initializer.
+     * Finds a static method of type (CallSite, Object[]) -> Object in the
+     * given class, and installs it on the caller.
+     * @throws IllegalArgumentException if there is no such method
+     */
+    public static
+    void registerBootstrapMethod(Class<?> runtime, String name) {
+        Class callc = Reflection.getCallerClass(2);
+        MethodHandle bootstrapMethod =
+            MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE);
+        // FIXME: exception processing wrong here
+        checkBSM(bootstrapMethod);
+        Linkage.registerBootstrapMethod(callc, bootstrapMethod);
+    }
+
+    /**
+     * Simplified version of registerBootstrapMethod for self-registration,
+     * to be called from a static initializer.
+     * Finds a static method of type (CallSite, Object[]) -> Object in the
+     * caller's class, and installs it on the caller.
+     * @throws IllegalArgumentException if there is no such method
+     */
+    public static
+    void registerBootstrapMethod(String name) {
+        Class callc = Reflection.getCallerClass(2);
+        MethodHandle bootstrapMethod =
+            MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE);
+        // FIXME: exception processing wrong here
+        checkBSM(bootstrapMethod);
+        Linkage.registerBootstrapMethod(callc, bootstrapMethod);
+    }
+
+    /**
+     * Report the bootstrap method registered for a given class.
+     * Returns null if the class has never yet registered a bootstrap method,
+     * or if the class has explicitly registered a null bootstrap method.
+     * Only callers privileged to set the bootstrap method may inquire
+     * about it, because a bootstrap method is potentially a back-door entry
+     * point into its class.
+     */
+    public static
+    MethodHandle getBootstrapMethod(Class callerClass) {
+        Class callc = Reflection.getCallerClass(2);
+        checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
+        synchronized (bootstrapMethods) {
+            return bootstrapMethods.get(callerClass);
+        }
+    }
+
+    /** The type of any bootstrap method is a three-argument method
+     * {@code (Class<?>, String, MethodType)} returning a {@code CallSite}.
+     */
+    public static final MethodType BOOTSTRAP_METHOD_TYPE
+            = MethodType.make(CallSite.class,
+                              Class.class, String.class, MethodType.class);
+
+    private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
+            = MethodType.make(Object.class,
+                              CallSite.class, Object[].class);
+
+    private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
+            new WeakHashMap<Class, MethodHandle>();
+
+    /**
+     * Invalidate all <code>invokedynamic</code> call sites everywhere.
+     * <p>
+     * When this method returns, every <code>invokedynamic</code> instruction
+     * will invoke its bootstrap method on next call.
+     * <p>
+     * It is unspecified whether call sites already known to the Java
+     * code will continue to be associated with <code>invokedynamic</code>
+     * instructions.  If any call site is still so associated, its
+     * {@link CallSite#getTarget()} method is guaranteed to return null
+     * the invalidation operation completes.
+     * <p>
+     * Invalidation operations are likely to be slow.  Use them sparingly.
+     */
+    public static
+    Object invalidateAll() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new LinkagePermission("invalidateAll"));
+        }
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    /**
+     * Invalidate all <code>invokedynamic</code> call sites associated
+     * with the given class.
+     * (These are exactly those sites which report the given class
+     * via the {@link CallSite#callerClass()} method.)
+     * <p>
+     * When this method returns, every matching <code>invokedynamic</code>
+     * instruction will invoke its bootstrap method on next call.
+     * <p>
+     * For additional semantics of call site invalidation,
+     * see {@link #invalidateAll()}.
+     */
+    public static
+    Object invalidateCallerClass(Class<?> callerClass) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
+        }
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    private static Object doNotBootstrap(CallSite site, Object... arguments) {
+        throw new UnsupportedOperationException("call site must not have null target: "+site);
+    }
+
+    private static final MethodHandle DO_NOT_BOOTSTRAP =
+            MethodHandles.Lookup.IMPL_LOOKUP.findStatic(Linkage.class, "doNotBootstrap",
+                OLD_BOOTSTRAP_METHOD_TYPE);
+
+    // Up-call from the JVM.  Obsolete.  FIXME: Delete from VM then from here.
+    static
+    MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
+        return DO_NOT_BOOTSTRAP;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/LinkagePermission.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,111 @@
+/*
+ * 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 java.dyn;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+/**
+ * This class is for runtime permissions. A RuntimePermission
+ * contains a name (also referred to as a "target name") but
+ * no actions list; you either have the named permission
+ * or you don't.
+ *
+ * <P>
+ * The target name is the name of the runtime permission (see below). The
+ * naming convention follows the  hierarchical property naming convention.
+ * Also, an asterisk
+ * may appear at the end of the name, following a ".", or by itself, to
+ * signify a wildcard match. For example: "loadLibrary.*" or "*" is valid,
+ * "*loadLibrary" or "a*b" is not valid.
+ * <P>
+ * The following table lists all the possible RuntimePermission target names,
+ * and for each provides a description of what the permission allows
+ * and a discussion of the risks of granting code the permission.
+ * <P>
+ *
+ * <table border=1 cellpadding=5 summary="permission target name,
+ *  what the target allows,and associated risks">
+ * <tr>
+ * <th>Permission Target Name</th>
+ * <th>What the Permission Allows</th>
+ * <th>Risks of Allowing this Permission</th>
+ * </tr>
+ *
+ * <tr>
+ *   <td>registerBootstrapMethod.{class name}</td>
+ *   <td>Specifying a bootstrap method for invokedynamic, within a class of the given name</td>
+ *   <td>An attacker could attempt to attach a bootstrap method to a class which
+ *       has just been loaded, thus gaining control of its invokedynamic calls.</td>
+ * </tr>
+ *
+ * <tr>
+ *   <td>invalidateAll</td>
+ *   <td>Force the relinking of invokedynamic call sites everywhere.</td>
+ *   <td>This could allow an attacker to slow down the system, or perhaps surface timing bugs in a dynamic language implementations, by forcing redundant relinking operations.</td>
+ * </tr>
+ *
+ *
+ * <tr>
+ *   <td>invalidateCallerClass.{class name}</td>
+ *   <td>Force the relinking of invokedynamic call sites in the given class.</td>
+ *   <td>See {@code invalidateAll}.</td>
+ * </tr>
+ * </table>
+ *
+ * @see java.security.BasicPermission
+ * @see java.lang.SecurityManager
+ *
+ * @author John Rose, JSR 292 EG
+ */
+
+public final class LinkagePermission extends BasicPermission {
+    /**
+     * Create a new LinkagePermission with the given name.
+     * The name is the symbolic name of the LinkagePermission, such as
+     * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
+     * may appear at the end of the name, following a ".", or by itself, to
+     * signify a wildcard match.
+     *
+     * @param name the name of the LinkagePermission
+     */
+    public LinkagePermission(String name) {
+        super(name);
+    }
+
+    /**
+     * Create a new LinkagePermission with the given name on the given class.
+     * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
+     *
+     * @param name the name of the LinkagePermission
+     * @param clazz the class affected by the permission
+     */
+    public LinkagePermission(String name, Class<?> clazz) {
+        super(name + "." + clazz.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/MethodHandle.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,135 @@
+/*
+ * 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 java.dyn;
+
+//import sun.dyn.*;
+
+import sun.dyn.Access;
+import sun.dyn.MethodHandleImpl;
+
+/**
+ * A method handle is a typed reference to the entry point of a method.
+ * <p>
+ * Method handles are strongly typed according to signature.
+ * They are not distinguished by method name or enclosing class.
+ * A method handle must be invoked under a signature which exactly matches
+ * the method handle's own type.
+ * <p>
+ * Every method handle confesses its type via the <code>type</code> accessor.
+ * The structure of this type is a series of classes, one of which is
+ * the return type of the method (or <code>void.class</code> if none).
+ * <p>
+ * Every method handle appears as an object containing a method named
+ * <code>invoke</code>, whose signature exactly matches
+ * the method handle's type.
+ * A normal Java method call (using the <code>invokevirtual</code> instruction)
+ * can invoke this method from Java source code (if language support is present).
+ * <p>
+ * Every call to a method handle specifies an intended method type,
+ * which must exactly match the type of the method handle.
+ * (The type is specified in the <code>invokevirtual</code> instruction,
+ * via a {@code CONSTANT_NameAndType} constant pool entry.)
+ * The call looks within the receiver object for a method
+ * named <code>invoke</code> of the intended method type.
+ * The call fails with a {@link WrongMethodTypeException}
+ * if the method does not exist, even if there is an <code>invoke</code>
+ * method of a closely similar signature.
+ * <p>
+ * A method handle is an unrestricted capability to call a method.
+ * A method handle can be formed on a non-public method by a class
+ * that has access to that method; the resulting handle can be used
+ * in any place by any caller who receives a reference to it.  Thus, access
+ * checking is performed when the method handle is created, not
+ * (as in reflection) every time it is called.  Handles to non-public
+ * methods, or in non-public classes, should generally be kept secret.
+ * They should not be passed to untrusted code.
+ * <p>
+ * Bytecode in an extended JVM can directly call a method handle's
+ * <code>invoke</code> from an <code>invokevirtual</code> instruction.
+ * The receiver class type must be <code>MethodHandle</code> and the method name
+ * must be <code>invoke</code>.  The signature of the invocation
+ * (after resolving symbolic type names) must exactly match the method type
+ * of the target method.
+ * <p>
+ * Bytecode in an extended JVM can directly obtain a method handle
+ * for any accessible method from a <code>ldc</code> instruction
+ * which refers to a <code>CONSTANT_Methodref</code> or
+ * <code>CONSTANT_InterfaceMethodref</code> constant pool entry.
+ * <p>
+ * All JVMs can also use a reflective API called <code>MethodHandles</code>
+ * for creating and calling method handles.
+ * <p>
+ * A method reference may refer either to a static or non-static method.
+ * In the non-static case, the method handle type includes an explicit
+ * receiver argument, prepended before any other arguments.
+ * In the method handle's type, the initial receiver argument is typed
+ * according to the class under which the method was initially requested.
+ * (E.g., if a non-static method handle is obtained via <code>ldc</code>,
+ * the type of the receiver is the class named in the constant pool entry.)
+ * <p>
+ * When a method handle to a virtual method is invoked, the method is
+ * always looked up in the receiver (that is, the first argument).
+ * <p>
+ * A non-virtual method handles to a specific virtual method implementation
+ * can also be created.  These do not perform virtual lookup based on
+ * receiver type.  Such a method handle simulates the effect of
+ * an <code>invokespecial</code> instruction to the same method.
+ *
+ * @see MethodType
+ * @see MethodHandles
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class MethodHandle
+        // Note: This is an implementation inheritance hack, and will be removed
+        // with a JVM change which moves the required hidden state onto this class.
+        extends MethodHandleImpl
+{
+    // interface MethodHandle<T extends MethodType<R,A...>>
+    // { T type(); <R,A...> public R invoke(A...); }
+
+    final private MethodType type;
+
+    /**
+     * Report the type of this method handle.
+     * Every invocation of this method handle must exactly match this type.
+     * @return the method handle type
+     */
+    public MethodType type() {
+        return type;
+    }
+
+    /**
+     * The constructor for MethodHandle may only be called by privileged code.
+     * Subclasses may be in other packages, but must possess
+     * a token which they obtained from MH with a security check.
+     * @param token non-null object which proves access permission
+     * @param type type (permanently assigned) of the new method handle
+     */
+    protected MethodHandle(Access token, MethodType type) {
+        super(token);
+        this.type = type;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/MethodHandles.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,1092 @@
+/*
+ * 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 java.dyn;
+
+import java.lang.reflect.Constructor;
+import sun.dyn.Access;
+import sun.dyn.MemberName;
+import sun.dyn.MethodHandleImpl;
+import sun.dyn.util.VerifyAccess;
+import sun.dyn.util.Wrapper;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import sun.dyn.Invokers;
+import sun.dyn.MethodTypeImpl;
+import sun.reflect.Reflection;
+import static sun.dyn.MemberName.newIllegalArgumentException;
+import static sun.dyn.MemberName.newNoAccessException;
+
+/**
+ * Fundamental operations and utilities for MethodHandle.
+ * <p>
+ * <em>API Note:</em>  The matching of method types in this API cannot
+ * be completely checked by Java's generic type system for three reasons:
+ * <ol>
+ * <li>Method types range over all possible arities,
+ * from no arguments to an arbitrary number of arguments.
+ * Generics are not variadic, and so cannot represent this.</li>
+ * <li>Method types can specify arguments of primitive types,
+ * which Java generic types cannot range over.</li>
+ * <li>Method types can optionally specify varargs (ellipsis).</li>
+ * </ol>
+ * @author John Rose, JSR 292 EG
+ */
+public class MethodHandles {
+
+    private MethodHandles() { }  // do not instantiate
+
+    private static final Access IMPL_TOKEN = Access.getToken();
+    private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
+    static { MethodHandleImpl.initStatics(); }
+    // See IMPL_LOOKUP below.
+
+    //// Method handle creation from ordinary methods.
+
+    public static Lookup lookup() {
+        return new Lookup();
+    }
+
+    /**
+     * A factory object for creating method handles, when the creation
+     * requires access checking.  Method handles do not perform
+     * access checks when they are called; this is a major difference
+     * from reflective {@link Method}, which performs access checking
+     * against every caller, on every call.  Method handle access
+     * restrictions are enforced when a method handle is created.
+     * The caller class against which those restrictions are enforced
+     * is known as the "lookup class".  {@link Lookup} embodies an
+     * authenticated lookup class, and can be used to create any number
+     * of access-checked method handles, all checked against a single
+     * lookup class.
+     * <p>
+     * A class which needs to create method handles will call
+     * {@code MethodHandles.lookup()} to create a factory for itself.
+     * It may then use this factory to create method handles on
+     * all of its methods, including private ones.
+     * It may also delegate the lookup (e.g., to a metaobject protocol)
+     * by passing the {@code Lookup} object to other code.
+     * If this other code creates method handles, they will be access
+     * checked against the original lookup class, and not with any higher
+     * privileges.
+     * <p>
+     * Note that access checks only apply to named and reflected methods.
+     * Other method handle creation methods, such as {@link #convertArguments},
+     * do not require any access checks, and can be done independently
+     * of any lookup class.
+     * <p>
+     * <em>A note about error conditions:<em>  A lookup can fail, because
+     * the containing class is not accessible to the lookup class, or
+     * because the desired class member is missing, or because the
+     * desired class member is not accessible to the lookup class.
+     * It can also fail if a security manager is installed and refuses
+     * access.  In any of these cases, an exception will be
+     * thrown from the attempted lookup.
+     * In general, the conditions under which a method handle may be
+     * created for a method M are exactly as restrictive as the conditions
+     * under which the lookup class could have compiled a call to M.
+     */
+    public static final
+    class Lookup {
+        private final Class<?> lookupClass;
+
+        /** Which class is performing the lookup?  It is this class against
+         *  which checks are performed for visibility and access permissions.
+         *  <p>
+         *  This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}.
+         */
+        public Class<?> lookupClass() {
+            return lookupClass;
+        }
+
+        /** Embody the current class (the lookupClass) as a lookup class
+         * for method handle creation.
+         * Must be called by from a method in this package,
+         * which in turn is called by a method not in this package.
+         * Also, don't make it private, lest javac interpose
+         * an access$N method.
+         */
+        Lookup() {
+            Class caller = getCallerClassAtEntryPoint();
+            // make sure we haven't accidentally picked up this class:
+            checkUnprivilegedlookupClass(caller);
+            this.lookupClass = caller;
+        }
+
+        private Lookup(Class<?> lookupClass) {
+            this.lookupClass = lookupClass;
+        }
+
+        /** Version of lookup which is trusted minimally.
+         *  It can only be used to create method handles to
+         *  publicly accessible members.
+         */
+        public static final Lookup PUBLIC_LOOKUP = new Lookup(null);
+
+        /** Package-private version of lookup which is trusted. */
+        static final Lookup IMPL_LOOKUP = new Lookup(Access.class);
+        static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
+
+        private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
+            if (lookupClass == null ||
+                lookupClass == Access.class ||
+                lookupClass.getName().startsWith("java.dyn."))
+                throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
+        }
+
+        @Override
+        public String toString() {
+            if (lookupClass == null)
+                return "public";
+            return lookupClass.getName();
+        }
+
+        // call this from an entry point method in Lookup with extraFrames=0.
+        private static Class<?> getCallerClassAtEntryPoint() {
+            final int CALLER_DEPTH = 4;
+            // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
+            // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
+            // Note:  This should be the only use of getCallerClass in this file.
+            return Reflection.getCallerClass(CALLER_DEPTH);
+        }
+
+        /**
+         * Produce a method handle for a static method.
+         * The type of the method handle will be that of the method.
+         * The method and all its argument types must be accessible to the lookup class.
+         * If the method's class has not yet been initialized, that is done
+         * immediately, before the method handle is returned.
+         * @param defc the class from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method
+         * @return the desired method handle
+         * @exception SecurityException <em>TBD</em>
+         * @exception NoAccessException if the method does not exist or access checking fails
+         */
+        public
+        MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
+            MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
+            checkStatic(true, method, lookupClass);
+            //throw NoSuchMethodException
+            return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
+        }
+
+        /**
+         * Produce a method handle for a virtual method.
+         * The type of the method handle will be that of the method,
+         * with the receiver type ({@code defc}) prepended.
+         * The method and all its argument types must be accessible to the lookup class.
+         * <p>
+         * When called, the handle will treat the first argument as a receiver
+         * and dispatch on the receiver's type to determine which method
+         * implementation to enter.
+         * (The dispatching action is identical with that performed by an
+         * {@code invokevirtual} or {@code invokeinterface} instruction.)
+         * @param defc the class or interface from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method, with the receiver argument omitted
+         * @return the desired method handle
+         * @exception SecurityException <em>TBD</em>
+         * @exception NoAccessException if the method does not exist or access checking fails
+         */
+        public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
+            MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass);
+            checkStatic(false, method, lookupClass);
+            return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
+        }
+
+        /**
+         * Produce an early-bound method handle for a virtual method,
+         * or a handle for a constructor, as if called from an {@code invokespecial}
+         * instruction from {@code caller}.
+         * The type of the method handle will be that of the method or constructor,
+         * with a suitably restricted receiver type (such as {@code caller}) prepended.
+         * The method or constructor and all its argument types must be accessible
+         * to the caller.
+         * <p>
+         * When called, the handle will treat the first argument as a receiver,
+         * but will not dispatch on the receiver's type.
+         * (This direct invocation action is identical with that performed by an
+         * {@code invokespecial} instruction.)
+         * <p>
+         * If the explicitly specified caller class is not identical with the
+         * lookup class, a security check TBD is performed.
+         * @param defc the class or interface from which the method is accessed
+         * @param name the name of the method, or "<init>" for a constructor
+         * @param type the type of the method, with the receiver argument omitted
+         * @param specialCaller the proposed calling class to perform the {@code invokespecial}
+         * @return the desired method handle
+         * @exception SecurityException <em>TBD</em>
+         * @exception NoAccessException if the method does not exist or access checking fails
+         */
+        public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
+                                        Class<?> specialCaller) throws NoAccessException {
+            checkSpecialCaller(specialCaller, lookupClass);
+            MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
+            checkStatic(false, method, lookupClass);
+            if (name.equals("<init>")) {
+                if (defc != specialCaller)
+                    throw newNoAccessException("constructor must be local to lookup class", method, lookupClass);
+            } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
+                throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass);
+            }
+            return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
+        }
+
+        /**
+         * Produce an early-bound method handle for a non-static method.
+         * The receiver must have a supertype {@code defc} in which a method
+         * of the given name and type is accessible to the lookup class.
+         * The method and all its argument types must be accessible to the lookup class.
+         * The type of the method handle will be that of the method.
+         * The given receiver will be bound into the method handle.
+         * <p>
+         * Equivalent to the following expression:
+         * <code>
+         * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
+         * </code>
+         * @param receiver the object from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method, with the receiver argument omitted
+         * @return the desired method handle
+         * @exception SecurityException <em>TBD</em>
+         * @exception NoAccessException if the method does not exist or access checking fails
+         */
+        public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
+            Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
+            MemberName reference = new MemberName(rcvc, name, type);
+            MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass);
+            checkStatic(false, method, lookupClass);
+            MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
+            MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
+            if (bmh == null)
+                throw newNoAccessException(method, lookupClass);
+            return bmh;
+        }
+
+        /**
+         * Make a direct method handle to <i>m</i>, if the lookup class has permission.
+         * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
+         * If <i>m</i> is virtual, overriding is respected on every call.
+         * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
+         * The type of the method handle will be that of the method,
+         * with the receiver type prepended (but only if it is non-static).
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
+         * @param m the reflected method
+         * @return a method handle which can invoke the reflected method
+         * @exception NoAccessException if access checking fails
+         */
+        public MethodHandle unreflect(Method m) throws NoAccessException {
+            return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass);
+        }
+
+        /**
+         * Produce a method handle for a reflected method.
+         * It will bypass checks for overriding methods on the receiver,
+         * as if by the {@code invokespecial} instruction.
+         * The type of the method handle will be that of the method,
+         * with the receiver type prepended.
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class,
+         * as if {@code invokespecial} instruction were being linked.
+         * @param m the reflected method
+         * @return a method handle which can invoke the reflected method
+         * @exception NoAccessException if access checking fails
+         */
+        public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
+            checkSpecialCaller(specialCaller, lookupClass);
+            MemberName mname = new MemberName(m);
+            checkStatic(false, mname, lookupClass);
+            return unreflectImpl(mname, m.isAccessible(), false, specialCaller);
+        }
+
+        /**
+         * Produce a method handle for a reflected constructor.
+         * The type of the method handle will be that of the constructor.
+         * The method handle will perform a {@code newInstance} operation,
+         * creating a new instance of the constructor's class on the
+         * arguments passed to the method handle.
+         * <p>
+         * If the constructor's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class,
+         * as if {@code invokespecial} instruction were being linked.
+         * @param ctor the reflected constructor
+         * @return a method handle which can invoke the reflected constructor
+         * @exception NoAccessException if access checking fails
+         */
+        public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException {
+            MemberName m = new MemberName(ctor);
+            return unreflectImpl(m, ctor.isAccessible(), false, lookupClass);
+        }
+
+        /**
+         * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+         * Produce a method handle giving read access to a reflected field.
+         * The type of the method handle will have a return type of the field's
+         * value type.  Its sole argument will be the field's containing class
+         * (but only if it is non-static).
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * @param f the reflected field
+         * @return a method handle which can load values from the reflected field
+         * @exception NoAccessException if access checking fails
+         */
+        public MethodHandle unreflectGetter(Field f) throws NoAccessException {
+            return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass);
+        }
+
+        /**
+         * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+         * Produce a method handle giving write access to a reflected field.
+         * The type of the method handle will have a void return type.
+         * Its last argument will be the field's value type.
+         * Its other argument will be the field's containing class
+         * (but only if it is non-static).
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * @param f the reflected field
+         * @return a method handle which can store values into the reflected field
+         * @exception NoAccessException if access checking fails
+         */
+        public MethodHandle unreflectSetter(Field f) throws NoAccessException {
+            return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass);
+        }
+
+    }
+
+    static /*must not be public*/
+    MethodHandle findStaticFrom(Class<?> lookupClass,
+                                Class<?> defc, String name, MethodType type) throws NoAccessException {
+        MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
+        checkStatic(true, method, lookupClass);
+        return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
+    }
+
+    static void checkStatic(boolean wantStatic, MemberName m, Class<?> lookupClass) {
+        if (wantStatic != m.isStatic()) {
+            String message = wantStatic ? "expected a static method" : "expected a non-static method";
+            throw newNoAccessException(message, m, lookupClass);
+        }
+    }
+
+    static void checkSpecialCaller(Class<?> specialCaller, Class<?> lookupClass) {
+        if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass())
+            return;  // privileged action
+        if (lookupClass == null ||  // public-only access
+            !VerifyAccess.isSamePackageMember(specialCaller, lookupClass))
+            throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass);
+    }
+
+    // Helper for creating handles on reflected methods and constructors.
+    static MethodHandle unreflectImpl(MemberName m, boolean isAccessible,
+                                      boolean doDispatch, Class<?> lookupClass) {
+        MethodType mtype = m.getInvocationType();
+        Class<?> defc = m.getDeclaringClass();
+        int mods = m.getModifiers();
+        if (m.isStatic()) {
+            if (!isAccessible &&
+                    VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null)
+                throw newNoAccessException(m, lookupClass);
+        } else {
+            Class<?> constraint;
+            if (isAccessible) {
+                // abbreviated access check for "unlocked" method
+                constraint = doDispatch ? defc : lookupClass;
+            } else {
+                constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass);
+            }
+            if (constraint != defc && !constraint.isAssignableFrom(defc)) {
+                if (!defc.isAssignableFrom(constraint))
+                    throw newNoAccessException("receiver must be in caller class", m, lookupClass);
+                mtype = mtype.changeParameterType(0, constraint);
+            }
+        }
+        return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle giving read access to elements of an array.
+     * The type of the method handle will have a return type of the array's
+     * element type.  Its first argument will be the array type,
+     * and the second will be {@code int}.
+     * @param arrayClass an array type
+     * @return a method handle which can load values from the given array type
+     * @throws  IllegalArgumentException if arrayClass is not an array type
+     */
+    public static
+    MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
+        return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle giving write access to elements of an array.
+     * The type of the method handle will have a void return type.
+     * Its last argument will be the array's element type.
+     * The first and second arguments will be the array type and int.
+     * @return a method handle which can store values into the array type
+     * @throws IllegalArgumentException if arrayClass is not an array type
+     */
+    public static
+    MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
+        return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
+    }
+
+
+    /// method handle invocation (reflective style)
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Call the {@code invoke} method of a given method handle,
+     * with arguments that exactly match the parameter types of the method handle.
+     * The length of the arguments array must equal the parameter count
+     * of the target's type.
+     * The arguments array is spread into separate arguments, and
+     * basic reference and unboxing conversions are applied.
+     * <p>
+     * In order to match the type of the target, the following argument
+     * conversions are applied as necessary:
+     * <ul>
+     * <li>reference casting
+     * <li>unboxing
+     * </ul>
+     * The following conversions are not applied:
+     * <ul>
+     * <li>primitive conversions (e.g., {@code byte} to {@code int}
+     * <li>varargs conversions other than the initial spread
+     * <li>any application-specific conversions (e.g., string to number)
+     * </ul>
+     * The result returned by the call is boxed if it is a primitive,
+     * or forced to null if the return type is void.
+     * <p>
+     * This call is a convenience method for the following code:
+     * <pre>
+     *   MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
+     *   Object result = invoker.invoke(arguments);
+     * </pre>
+     * @param target the method handle to invoke
+     * @param arguments the arguments to pass to the target
+     * @return the result returned by the target
+     */
+    public static
+    Object invoke(MethodHandle target, Object... arguments) {
+        int argc = arguments == null ? 0 : arguments.length;
+        MethodType type = target.type();
+        if (argc <= 4) {
+            MethodHandle invoker = invokers(type).genericInvoker();
+            switch (argc) {
+                case 0:  return invoker.<Object>invoke(target);
+                case 1:  return invoker.<Object>invoke(target,
+                                    arguments[0]);
+                case 2:  return invoker.<Object>invoke(target,
+                                    arguments[0], arguments[1]);
+                case 3:  return invoker.<Object>invoke(target,
+                                    arguments[0], arguments[1], arguments[2]);
+                case 4:  return invoker.<Object>invoke(target,
+                                    arguments[0], arguments[1], arguments[2], arguments[3]);
+            }
+        }
+        MethodHandle invoker = invokers(type).varargsInvoker();
+        return invoker.<Object>invoke(target, arguments);
+    }
+
+    public static
+    Object invoke_0(MethodHandle target) {
+        MethodHandle invoker = invokers(target.type()).genericInvoker();
+        return invoker.<Object>invoke(target);
+    }
+    public static
+    Object invoke_1(MethodHandle target, Object a0) {
+        MethodHandle invoker = invokers(target.type()).genericInvoker();
+        return invoker.<Object>invoke(target, a0);
+    }
+    public static
+    Object invoke_2(MethodHandle target, Object a0, Object a1) {
+        MethodHandle invoker = invokers(target.type()).genericInvoker();
+        return invoker.<Object>invoke(target, a0, a1);
+    }
+    public static
+    Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) {
+        MethodHandle invoker = invokers(target.type()).genericInvoker();
+        return invoker.<Object>invoke(target, a0, a1, a2);
+    }
+    public static
+    Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) {
+        MethodHandle invoker = invokers(target.type()).genericInvoker();
+        return invoker.<Object>invoke(target, a0, a1, a2, a3);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Give a method handle which will invoke any method handle of the
+     * given type on a standard set of {@code Object} type arguments.
+     * The the resulting invoker will be a method handle with the following
+     * arguments:
+     * <ul>
+     * <li>a single {@code MethodHandle} target
+     * <li>zero or more {@code Object} values
+     * <li>an optional {@code Object[]} array containing more arguments
+     * </ul>
+     * The invoker will spread the varargs array (if present), apply
+     * reference casts as necessary, and unbox primitive arguments.
+     * The return value of the invoker will be an {@code Object} reference,
+     * boxing a primitive value if the original type returns a primitive,
+     * and always null if the original type returns void.
+     * <p>
+     * This is a convenience method equivalent to the following code:
+     * <pre>
+     * MethodHandle invoker = exactInvoker(type);
+     * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
+     * genericType = genericType.insertParameterType(0, MethodHandle.class);
+     * if (!varargs)
+     *     return convertArguments(invoker, genericType);
+     * else
+     *     return spreadArguments(invoker, genericType);
+     * </pre>
+     * @param type the desired target type
+     * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
+     * @param varargs if true, the invoker will accept a final {@code Object[]} argument
+     * @return a method handle suitable for invoking any method handle of the given type
+     */
+    static public
+    MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
+        return invokers(type).genericInvoker();
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Give a method handle which will take a invoke any method handle of the
+     * given type.  The resulting invoker will have a type which is
+     * exactly equal to the desired type, except that it will accept
+     * an additional leading argument of type {@code MethodHandle}.
+     * <p>
+     * This is a convenience method equivalent to the following code:
+     * <pre>
+     *     MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
+     * </pre>
+     * @param type the desired target type
+     * @return a method handle suitable for invoking any method handle of the given type
+     */
+    static public
+    MethodHandle exactInvoker(MethodType type) {
+        return invokers(type).exactInvoker();
+    }
+
+    static private Invokers invokers(MethodType type) {
+        return MethodTypeImpl.invokers(IMPL_TOKEN, type);
+    }
+
+    /**
+     * <em>WORK IN PROGRESS:</em>
+     * Perform value checking, exactly as if for an adapted method handle.
+     * It is assumed that the given value is either null, of type T0,
+     * or (if T0 is primitive) of the wrapper type corresponding to T0.
+     * The following checks and conversions are made:
+     * <ul>
+     * <li>If T0 and T1 are references, then a cast to T1 is applied.
+     *     (The types do not need to be related in any particular way.)
+     * <li>If T0 and T1 are primitives, then a widening or narrowing
+     *     conversion is applied, if one exists.
+     * <li>If T0 is a primitive and T1 a reference, and
+     *     T0 has a wrapper type TW, a boxing conversion to TW is applied,
+     *     possibly followed by a reference conversion.
+     *     T1 must be TW or a supertype.
+     * <li>If T0 is a reference and T1 a primitive, and
+     *     T1 has a wrapper type TW, an unboxing conversion is applied,
+     *     possibly preceded by a reference conversion.
+     *     T0 must be TW or a supertype.
+     * <li>If T1 is void, the return value is discarded
+     * <li>If T0 is void and T1 a reference, a null value is introduced.
+     * <li>If T0 is void and T1 a primitive, a zero value is introduced.
+     * </ul>
+     * If the value is discarded, null will be returned.
+     * @param valueType
+     * @param value
+     * @return the value, converted if necessary
+     * @throws java.lang.ClassCastException if a cast fails
+     */
+    static
+    <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
+       throws ClassCastException
+    {
+        if (t0 == t1) {
+            // no conversion needed; just reassert the same type
+            if (t0.isPrimitive())
+                return Wrapper.asPrimitiveType(t1).cast(value);
+            else
+                return Wrapper.OBJECT.cast(value, t1);
+        }
+        boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
+        if (!prim0) {
+            // check contract with caller
+            Wrapper.OBJECT.cast(value, t0);
+            if (!prim1) {
+                return Wrapper.OBJECT.cast(value, t1);
+            }
+            // convert reference to primitive by unboxing
+            Wrapper w1 = Wrapper.forPrimitiveType(t1);
+            return w1.cast(value, t1);
+        }
+        // check contract with caller:
+        Wrapper.asWrapperType(t0).cast(value);
+        Wrapper w1 = Wrapper.forPrimitiveType(t1);
+        return w1.cast(value, t1);
+    }
+
+    static
+    Object checkValue(Class<?> T1, Object value)
+       throws ClassCastException
+    {
+        Class<?> T0;
+        if (value == null)
+            T0 = Object.class;
+        else
+            T0 = value.getClass();
+        return checkValue(T0, T1, value);
+    }
+
+    /// method handle modification (creation from other method handles)
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which adapts the type of the
+     * given method handle to a new type, by pairwise argument conversion,
+     * and/or varargs conversion.
+     * The original type and new type must have the same number of
+     * arguments, or else one or both them the must be varargs types.
+     * The resulting method handle is guaranteed to confess a type
+     * which is equal to the desired new type, with any varargs property erased.
+     * <p>
+     * If the original type and new type are equal, returns target.
+     * <p>
+     * The following conversions are applied as needed both to
+     * arguments and return types.  Let T0 and T1 be the differing
+     * new and old parameter types (or old and new return types)
+     * for corresponding values passed by the new and old method types.
+     * <p>
+     * If an ordinary (non-varargs) parameter of the new type is
+     * to be boxed in a varargs parameter of the old type of type T1[],
+     * then T1 is the element type of the varargs array.
+     * Otherwise, if a varargs parameter of the new type of type T0[]
+     * is to be spread into one or more outgoing old type parameters,
+     * then T0 is the element type of the
+     * If the new type is varargs and the old type is not, the varargs
+     * argument will be checked and must be a non-null array of exactly
+     * the right length.  If there are no parameters in the old type
+     * corresponding to the new varargs parameter, the varargs argument
+     * is also allowed to be null.
+     * <p>
+     * Given those types T0, T1, one of the following conversions is applied
+     * if possible:
+     * <ul>
+     * <li>If T0 and T1 are references, then a cast to T2 is applied,
+     *     where T2 is Object if T1 is an interface, else T1.
+     *     (The types do not need to be related in any particular way.
+     *     The treatment of interfaces follows the usage of the bytecode verifier.)
+     * <li>If T0 and T1 are primitives, then a Java casting
+     *     conversion (JLS 5.5) is applied, if one exists.
+     * <li>If T0 and T1 are primitives and one is boolean,
+     *     the boolean is treated as a one-bit unsigned integer.
+     *     (This treatment follows the usage of the bytecode verifier.)
+     *     A conversion from another primitive type behaves as if
+     *     it first converts to byte, and then masks all but the low bit.
+     * <li>If T0 is a primitive and T1 a reference, a boxing
+     *     conversion is applied if one exists, possibly followed by
+     *     an reference conversion to a superclass.
+     *     T1 must be a wrapper class or a supertype of one.
+     *     If T1 is a wrapper class, T0 is converted if necessary
+     *     to T1's primitive type by one of the preceding conversions.
+     *     Otherwise, T0 is boxed, and its wrapper converted to T1.
+     * <li>If T0 is a reference and T1 a primitive, an unboxing
+     *     conversion is applied if one exists, possibly preceded by
+     *     a reference conversion to a wrapper class.
+     *     T0 must be a wrapper class or a supertype of one.
+     *     If T0 is a wrapper class, its primitive value is converted
+     *     if necessary to T1 by one of the preceding conversions.
+     *     Otherwise, T0 is converted directly to the wrapper type for T1,
+     *     which is then unboxed.
+     * <li>If T1 is void, any returned value is discarded
+     * <li>If T0 is void and T1 a reference, a null value is introduced.
+     * <li>If T0 is void and T1 a primitive, a zero value is introduced.
+     * </ul>
+     * @param target the method handle to invoke after arguments are retyped
+     * @param newType the expected type of the new method handle
+     * @return a method handle which delegates to {@code target} after performing
+     *           any necessary argument conversions, and arranges for any
+     *           necessary return value conversions
+     * @throws WrongMethodTypeException if the conversion cannot be made
+     */
+    public static
+    MethodHandle convertArguments(MethodHandle target, MethodType newType) {
+        MethodType oldType = target.type();
+        if (oldType.equals(newType))
+            return target;
+        MethodHandle res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
+                                                 newType, oldType, null);
+        if (res == null)
+            throw newIllegalArgumentException("cannot convert to "+newType+": "+target);
+        return res;
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which adapts the calling sequence of the
+     * given method handle to a new type, by reordering the arguments.
+     * The resulting method handle is guaranteed to confess a type
+     * which is equal to the desired new type.
+     * <p>
+     * The given array controls the reordering.
+     * Call {@code #I} the number of incoming parameters (the value
+     * {@code newType.parameterCount()}, and call {@code #O} the number
+     * of outgoing parameters (the value {@code target.type().parameterCount()}).
+     * Then the length of the reordering array must be {@code #O},
+     * and each element must be a non-negative number less than {@code #I}.
+     * For every {@code N} less than {@code #O}, the {@code N}-th
+     * outgoing argument will be taken from the {@code I}-th incoming
+     * argument, where {@code I} is {@code reorder[N]}.
+     * <p>
+     * The reordering array need not specify an actual permutation.
+     * An incoming argument will be duplicated if its index appears
+     * more than once in the array, and an incoming argument will be dropped
+     * if its index does not appear in the array.
+     * <p>
+     * Pairwise conversions are applied as needed to arguments and return
+     * values, as with {@link #convertArguments}.
+     * @param target the method handle to invoke after arguments are reordered
+     * @param newType the expected type of the new method handle
+     * @param reorder a string which controls the reordering
+     * @return a method handle which delegates to {@code target} after performing
+     *           any necessary argument motion and conversions, and arranges for any
+     *           necessary return value conversions
+     */
+    public static
+    MethodHandle permuteArguments(MethodHandle target, MethodType newType, int[] reorder) {
+        MethodType oldType = target.type();
+        checkReorder(reorder, newType, oldType);
+        return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
+                                                 newType, oldType,
+                                                 reorder);
+    }
+
+    private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
+        if (reorder.length == oldType.parameterCount()) {
+            int limit = newType.parameterCount();
+            boolean bad = false;
+            for (int i : reorder) {
+                if (i < 0 || i >= limit) {
+                    bad = true; break;
+                }
+            }
+            if (!bad)  return;
+        }
+        throw newIllegalArgumentException("bad reorder array");
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which adapts the type of the
+     * given method handle to a new type, by spreading the final argument.
+     * The resulting method handle is guaranteed to confess a type
+     * which is equal to the desired new type.
+     * <p>
+     * The final parameter type of the new type must be an array type T[].
+     * This is the type of what is called the <i>spread</i> argument.
+     * All other arguments of the new type are called <i>ordinary</i> arguments.
+     * <p>
+     * The ordinary arguments of the new type are pairwise converted
+     * to the initial parameter types of the old type, according to the
+     * rules in {@link #convertArguments}.
+     * Any additional arguments in the old type
+     * are converted from the array element type T,
+     * again according to the rules in {@link #convertArguments}.
+     * The return value is converted according likewise.
+     * <p>
+     * The call verifies that the spread argument is in fact an array
+     * of exactly the type length, i.e., the excess number of
+     * arguments in the old type over the ordinary arguments in the new type.
+     * If there are no excess arguments, the spread argument is also
+     * allowed to be null.
+     * @param target the method handle to invoke after the argument is prepended
+     * @param newType the expected type of the new method handle
+     * @return a new method handle which spreads its final argument,
+     *         before calling the original method handle
+     */
+    public static
+    MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
+        MethodType oldType = target.type();
+        int inargs  = newType.parameterCount();
+        int outargs = oldType.parameterCount();
+        int spreadPos = inargs - 1;
+        int numSpread = (outargs - spreadPos);
+        MethodHandle res = null;
+        if (spreadPos >= 0 && numSpread >= 0) {
+            res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos);
+        }
+        if (res == null) {
+            throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
+        }
+        return res;
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which adapts the type of the
+     * given method handle to a new type, by collecting a series of
+     * trailing arguments into an array.
+     * The resulting method handle is guaranteed to confess a type
+     * which is equal to the desired new type.
+     * <p>
+     * This method is inverse to {@link #spreadArguments}.
+     * The final parameter type of the old type must be an array type T[],
+     * which is the type of what is called the <i>spread</i> argument.
+     * The trailing arguments of the new type which correspond to
+     * the spread argument are all converted to type T and collected
+     * into an array before the original method is called.
+     * <p>
+     * ISSUE: Unify this with combineArguments.  CollectArguments
+     * is combineArguments with (a) new Object[]{...} as a combiner,
+     * and (b) the combined arguments dropped, in favor of the combined result.
+     * @param target the method handle to invoke after the argument is prepended
+     * @param newType the expected type of the new method handle
+     * @return a new method handle which collects some trailings argument
+     *         into an array, before calling the original method handle
+     */
+    public static
+    MethodHandle collectArguments(MethodHandle target, MethodType newType) {
+        MethodType oldType = target.type();
+        int inargs  = newType.parameterCount();
+        int outargs = oldType.parameterCount();
+        int collectPos = outargs - 1;
+        int numCollect = (inargs - collectPos);
+        if (collectPos < 0 || numCollect < 0)
+            throw newIllegalArgumentException("wrong number of arguments");
+        return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which calls the original method handle,
+     * after inserting the given argument at the given position.
+     * The type of the new method handle will drop the corresponding argument
+     * type from the original handle's type.
+     * <p>
+     * The given argument object must match the dropped argument type.
+     * If the dropped argument type is a primitive, the argument object
+     * must be a wrapper, and is unboxed to produce the primitive.
+     * <p>
+     * The  <i>pos</i> may range between zero and <i>N</i> (inclusively),
+     * where <i>N</i> is the number of argument types in <i>target</i>,
+     * meaning to insert the new argument as the first or last (respectively),
+     * or somewhere in between.
+     * @param target the method handle to invoke after the argument is inserted
+     * @param pos where to insert the argument (zero for the first)
+     * @param value the argument to insert
+     * @return a new method handle which inserts an additional argument,
+     *         before calling the original method handle
+     */
+    public static
+    MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
+        MethodType oldType = target.type();
+        ArrayList<Class<?>> ptypes =
+                new ArrayList<Class<?>>(oldType.parameterList());
+        int outargs = oldType.parameterCount();
+        int inargs  = outargs - 1;
+        if (pos < 0 || pos >= outargs)
+            throw newIllegalArgumentException("no argument type to append");
+        Class<?> valueType = ptypes.remove(pos);
+        value = checkValue(valueType, value);
+        if (pos == 0 && !valueType.isPrimitive()) {
+            // At least for now, make bound method handles a special case.
+            // This lets us get by with minimal JVM support, at the expense
+            // of generating signature-specific adapters as Java bytecodes.
+            MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
+            if (bmh != null)  return bmh;
+            // else fall through to general adapter machinery
+        }
+        return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Produce a method handle which calls the original method handle,
+     * after dropping the given argument(s) at the given position.
+     * The type of the new method handle will insert the given argument
+     * type(s), at that position, into the original handle's type.
+     * <p>
+     * The <i>pos</i> may range between zero and <i>N-1</i>,
+     * where <i>N</i> is the number of argument types in <i>target</i>,
+     * meaning to drop the first or last argument (respectively),
+     * or an argument somewhere in between.
+     * @param target the method handle to invoke after the argument is dropped
+     * @param valueTypes the type(s) of the argument to drop
+     * @param pos which argument to drop (zero for the first)
+     * @return a new method handle which drops an argument of the given type,
+     *         before calling the original method handle
+     */
+    public static
+    MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
+        if (valueTypes.length == 0)  return target;
+        MethodType oldType = target.type();
+        int outargs = oldType.parameterCount();
+        int inargs  = outargs + valueTypes.length;
+        if (pos < 0 || pos >= inargs)
+            throw newIllegalArgumentException("no argument type to remove");
+        ArrayList<Class<?>> ptypes =
+                new ArrayList<Class<?>>(oldType.parameterList());
+        ptypes.addAll(pos, Arrays.asList(valueTypes));
+        MethodType newType = MethodType.make(oldType.returnType(), ptypes);
+        return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Make a method handle which adapts a target method handle,
+     * by guarding it with a test, a boolean-valued method handle.
+     * If the guard fails, a fallback handle is called instead.
+     * All three method handles must have the same corresponding
+     * argument and return types, except that the return type
+     * of the test must be boolean.
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>
+     * signature T(A...);
+     * boolean test(A...);
+     * T target(A...);
+     * T fallback(A...);
+     * T adapter(A... a) {
+     *   if (test(a...))
+     *     return target(a...);
+     *   else
+     *     return fallback(a...);
+     * }
+     * </pre></blockquote>
+     * @param test method handle used for test, must return boolean
+     * @param target method handle to call if test passes
+     * @param fallback method handle to call if test fails
+     * @return method handle which incorporates the specified if/then/else logic
+     * @throws IllegalArgumentException if {@code test} does not return boolean,
+     *          or if all three method types do not match (with the return
+     *          type of {@code test} changed to match that of {@code target}).
+     */
+    public static
+    MethodHandle guardWithTest(MethodHandle test,
+                               MethodHandle target,
+                               MethodHandle fallback) {
+        if (target.type() != fallback.type())
+            throw newIllegalArgumentException("target and fallback types do not match");
+        if (target.type().changeReturnType(boolean.class) != test.type())
+            throw newIllegalArgumentException("target and test types do not match");
+        /* {
+            MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
+            static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
+                return z ? t : f;
+            }
+            static MethodHandle compose(MethodHandle f, MethodHandle g) {
+                Class<?> initargs = g.type().parameterArray();
+                f = dropArguments(f, 1, initargs);  // ignore 2nd copy of args
+                return combineArguments(f, g);
+            }
+            // choose = \z.(z ? target : fallback)
+            MethodHandle choose = findVirtual(MethodHandles.class, "choose",
+                    MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
+            choose = appendArgument(choose, target);
+            choose = appendArgument(choose, fallback);
+            MethodHandle dispatch = compose(choose, test);
+            // dispatch = \(a...).(test(a...) ? target : fallback)
+            return combineArguments(invoke, dispatch, 0);
+            // return \(a...).((test(a...) ? target : fallback).invoke(a...))
+        } */
+        return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
+    }
+
+    /**
+     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+     * Adapt a target method handle {@code target} by first processing
+     * its arguments, and then calling the target.
+     * The initial processing is performed by a second method handle, the {@code combiner}.
+     * After this, control passes to the {@code target}, with the same arguments.
+     * <p>
+     * The return value of the {@code combiner} is inserted into the argument list
+     * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
+     * Except for this inserted argument (if any), the argument types of
+     * the target {@code target} and the {@code combiner} must be identical.
+     * <p>
+     * (Note that {@link #dropArguments} can be used to remove any arguments
+     * that either the {@code combiner} or {@code target} does not wish to receive.)
+     * <p>
+     * The combiner handle must have the same argument types as the
+     * target handle, but must return {@link MethodHandle} instead of
+     * the ultimate return type.  The returned method handle, in turn,
+     * is required to have exactly the given final method type.
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>
+     * signature V(A[pos]..., B...);
+     * signature T(A[pos]..., V, B...);
+     * T target(A... a, V v, B... b);
+     * V combiner(A..., B...);
+     * T adapter(A... a, B... b) {
+     *   V v = combiner(a..., b...);
+     *   return target(a..., v, b...);
+     * }
+     * </pre></blockquote>
+     * @param target the method handle to invoke after arguments are combined
+     * @param pos where the return value of {@code combiner} is to
+     *          be inserted as an argument to {@code target}
+     * @param combiner method handle to call initially on the incoming arguments
+     * @return method handle which incorporates the specified dispatch logic
+     * @throws IllegalArgumentException if {@code combiner} does not itself
+     *          return either void or the {@code pos}-th argument of {@code target},
+     *          or does not have the same argument types as {@code target}
+     *          (minus the inserted argument)
+     */
+    public static
+    MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
+        MethodType mhType = target.type();
+        Class<?> combineType = combiner.type().returnType();
+        MethodType incomingArgs;
+        if (pos < 0) {
+            // No inserted argument; target & combiner must have same argument types.
+            incomingArgs = mhType;
+            if (!incomingArgs.changeReturnType(combineType).equals(combiner.type()))
+                throw newIllegalArgumentException("target and combiner types do not match");
+        } else {
+            // Inserted argument.
+            if (pos >= mhType.parameterCount()
+                || mhType.parameterType(pos) != combineType)
+                throw newIllegalArgumentException("inserted combiner argument does not match target");
+            incomingArgs = mhType.dropParameterType(pos);
+        }
+        if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
+            throw newIllegalArgumentException("target and combiner types do not match");
+        }
+        return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/MethodType.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,575 @@
+/*
+ * 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 java.dyn;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import sun.dyn.Access;
+import sun.dyn.Invokers;
+import sun.dyn.MethodTypeImpl;
+import sun.dyn.util.BytecodeSignature;
+import static sun.dyn.MemberName.newIllegalArgumentException;
+
+/**
+ * Run-time token used to match call sites with method handles.
+ * The structure is a return type accompanied by any number of parameter types.
+ * The types (primitive, void, and reference) are represented by Class objects.
+ * All instances of <code>MethodType</code> are immutable.
+ * Two instances are completely interchangeable if they compare equal.
+ * Equality depends exactly on the return and parameter types.
+ * <p>
+ * This type can be created only by factory methods, which manage interning.
+ *
+ * @author John Rose, JSR 292 EG
+ */
+public final
+class MethodType {
+    private final Class<?>   rtype;
+    private final Class<?>[] ptypes;
+    private MethodTypeForm form; // erased form, plus cached data about primitives
+    private MethodType wrapAlt;  // alternative wrapped/unwrapped version
+    private Invokers invokers;   // cache of handy higher-order adapters
+
+    private static final Access IMPL_TOKEN = Access.getToken();
+
+    // share a cache with a friend in this package
+    Invokers getInvokers() { return invokers; }
+    void setInvokers(Invokers inv) { invokers = inv; }
+
+    static {
+        // This hack allows the implementation package special access to
+        // the internals of MethodType.  In particular, the Form has all sorts
+        // of cached information useful to the implementation code.
+        MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
+            public Class<?>[] ptypes(MethodType mt)        { return mt.ptypes; }
+            public MethodTypeImpl form(MethodType mt)      { return mt.form; }
+            public void setForm(MethodType mt, MethodTypeImpl form) {
+                assert(mt.form == null);
+                mt.form = (MethodTypeForm) form;
+            }
+            public MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+                return MethodType.makeImpl(rtype, ptypes, trusted);
+            }
+            public MethodTypeImpl newMethodTypeForm(MethodType mt) {
+                return new MethodTypeForm(mt);
+            }
+            public Invokers getInvokers(MethodType mt)    { return mt.invokers; }
+            public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; }
+        });
+    }
+
+    private MethodType(Class<?> rtype, Class<?>[] ptypes) {
+        checkRtype(rtype);
+        checkPtypes(ptypes);
+        this.rtype = rtype;
+        this.ptypes = ptypes;
+    }
+
+    private void checkRtype(Class<?> rtype) {
+        rtype.equals(rtype);  // null check
+    }
+    private void checkPtypes(Class<?>[] ptypes) {
+        for (Class<?> ptype : ptypes) {
+            ptype.equals(ptype);  // null check
+            if (ptype == void.class)
+                throw newIllegalArgumentException("void parameter: "+this);
+        }
+    }
+
+    static final HashMap<MethodType,MethodType> internTable
+            = new HashMap<MethodType, MethodType>();
+
+    static final Class<?>[] NO_PTYPES = {};
+
+    /** Find or create an instance of the given method type.
+     * @param rtype  the return type
+     * @param ptypes the parameter types
+     * @return the interned method type with the given parts
+     * @throws NullPointerException if rtype or any ptype is null
+     * @throws IllegalArgumentException if any of the ptypes is void
+     */
+    public static
+    MethodType make(Class<?> rtype, Class<?>[] ptypes) {
+        return makeImpl(rtype, ptypes, false);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. */
+    public static
+    MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
+        return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     *  The leading parameter type is prepended to the remaining array.
+     */
+    public static
+    MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
+        Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
+        ptypes1[0] = ptype0;
+        System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
+        return makeImpl(rtype, ptypes1, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     *  The resulting method has no parameter types.
+     */
+    public static
+    MethodType make(Class<?> rtype) {
+        return makeImpl(rtype, NO_PTYPES, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     *  The resulting method has the single given parameter type.
+     */
+    public static
+    MethodType make(Class<?> rtype, Class<?> ptype0) {
+        return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     *  The resulting method has the same parameter types as {@code ptypes},
+     *  and the specified return type.
+     */
+    public static
+    MethodType make(Class<?> rtype, MethodType ptypes) {
+        return makeImpl(rtype, ptypes.ptypes, true);
+    }
+
+    /**
+     * Sole factory method to find or create an interned method type.
+     * @param rtype desired return type
+     * @param ptypes desired parameter types
+     * @param trusted whether the ptypes can be used without cloning
+     * @return the unique method type of the desired structure
+     */
+    private static
+    MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+        if (ptypes == null || ptypes.length == 0) {
+            ptypes = NO_PTYPES; trusted = true;
+        }
+        MethodType mt1 = new MethodType(rtype, ptypes);
+        MethodType mt0;
+        synchronized (internTable) {
+            mt0 = internTable.get(mt1);
+            if (mt0 != null)
+                return mt0;
+        }
+        if (!trusted)
+            // defensively copy the array passed in by the user
+            mt1 = new MethodType(rtype, ptypes.clone());
+        // promote the object to the Real Thing, and reprobe
+        MethodTypeImpl.initForm(IMPL_TOKEN, mt1);
+        synchronized (internTable) {
+            mt0 = internTable.get(mt1);
+            if (mt0 != null)
+                return mt0;
+            internTable.put(mt1, mt1);
+        }
+        return mt1;
+    }
+
+    // Entry point from JVM.  TODO: Change the name & signature.
+    private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes,
+            boolean ignore1, boolean ignore2) {
+        return makeImpl(rtype, ptypes, true);
+    }
+
+    private static final MethodType[] objectOnlyTypes = new MethodType[20];
+
+    /**
+     * Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
+     * All parameters and the return type will be Object, except the final varargs parameter if any.
+     * @param objectArgCount number of parameters (excluding the varargs parameter if any)
+     * @param varargs whether there will be a varargs parameter, of type Object[]
+     * @return a totally generic method type, given only its count of parameters and varargs
+     * @see #makeGeneric(int)
+     */
+    public static
+    MethodType makeGeneric(int objectArgCount, boolean varargs) {
+        MethodType mt;
+        int ivarargs = (!varargs ? 0 : 1);
+        int ootIndex = objectArgCount*2 + ivarargs;
+        if (ootIndex < objectOnlyTypes.length) {
+            mt = objectOnlyTypes[ootIndex];
+            if (mt != null)  return mt;
+        }
+        Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
+        Arrays.fill(ptypes, Object.class);
+        if (ivarargs != 0)  ptypes[objectArgCount] = Object[].class;
+        mt = makeImpl(Object.class, ptypes, true);
+        if (ootIndex < objectOnlyTypes.length) {
+            objectOnlyTypes[ootIndex] = mt;     // cache it here also!
+        }
+        return mt;
+    }
+
+    /**
+     * All parameters and the return type will be Object.
+     * @param objectArgCount number of parameters
+     * @return a totally generic method type, given only its count of parameters
+     * @see #makeGeneric(int, boolean)
+     */
+    public static
+    MethodType makeGeneric(int objectArgCount) {
+        return makeGeneric(objectArgCount, false);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
+     * @param num    the index (zero-based) of the parameter type to change
+     * @param nptype a new parameter type to replace the old one with
+     * @return the same type, except with the selected parameter changed
+     */
+    public MethodType changeParameterType(int num, Class<?> nptype) {
+        if (parameterType(num) == nptype)  return this;
+        Class<?>[] nptypes = ptypes.clone();
+        nptypes[num] = nptype;
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
+     * @param num    the position (zero-based) of the inserted parameter type
+     * @param nptype a new parameter type to insert into the parameter list
+     * @return the same type, except with the selected parameter inserted
+     */
+    public MethodType insertParameterType(int num, Class<?> nptype) {
+        int len = ptypes.length;
+        Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
+        System.arraycopy(nptypes, num, nptypes, num+1, len-num);
+        nptypes[num] = nptype;
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
+     * @param num    the index (zero-based) of the parameter type to remove
+     * @return the same type, except with the selected parameter removed
+     */
+    public MethodType dropParameterType(int num) {
+        int len = ptypes.length;
+        Class<?>[] nptypes;
+        if (num == 0) {
+            nptypes = Arrays.copyOfRange(ptypes, 1, len);
+        } else {
+            nptypes = Arrays.copyOfRange(ptypes, 0, len-1);
+            System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num);
+        }
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
+     * @param nrtype a return parameter type to replace the old one with
+     * @return the same type, except with the return type change
+     */
+    public MethodType changeReturnType(Class<?> nrtype) {
+        if (returnType() == nrtype)  return this;
+        return makeImpl(nrtype, ptypes, true);
+    }
+
+    /** Convenience method.
+     * Report if this type contains a primitive argument or return value.
+     * @return true if any of the types are primitives
+     */
+    public boolean hasPrimitives() {
+        return form.hasPrimitives();
+    }
+
+    /** Convenience method.
+     * Report if this type contains a wrapper argument or return value.
+     * Wrappers are types which box primitive values, such as {@link Integer}.
+     * @return true if any of the types are wrappers
+     */
+    public boolean hasWrappers() {
+        return unwrap() != this;
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     * Erase all reference types to Object.
+     * @return a version of the original type with all reference types replaced
+     */
+    public MethodType erase() {
+        return form.erasedType();
+    }
+
+    /** Convenience method for {@link #makeGeneric(int)}.
+     * Convert all types, both reference and primitive, to Object.
+     * @return a version of the original type with all types replaced
+     */
+    public MethodType generic() {
+        return makeGeneric(parameterCount());
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     * Convert all primitive types to their corresponding wrapper types.
+     * A {@code void} return type is changed to the type {@code java.lang.Void}.
+     * @return a version of the original type with all primitive types replaced
+     */
+    public MethodType wrap() {
+        return hasPrimitives() ? wrapWithPrims(this) : this;
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     * Convert all wrapper types to their corresponding primitive types.
+     * A return type of {@java.lang.Void} is changed to {@code void}.
+     * @return a version of the original type with all wrapper types replaced
+     */
+    public MethodType unwrap() {
+        MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
+        return unwrapWithNoPrims(noprims);
+    }
+
+    private static MethodType wrapWithPrims(MethodType pt) {
+        assert(pt.hasPrimitives());
+        MethodType wt = pt.wrapAlt;
+        if (wt == null) {
+            // fill in lazily
+            wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP);
+            assert(wt != null);
+            pt.wrapAlt = wt;
+        }
+        return wt;
+    }
+
+    private static MethodType unwrapWithNoPrims(MethodType wt) {
+        assert(!wt.hasPrimitives());
+        MethodType uwt = wt.wrapAlt;
+        if (uwt == null) {
+            // fill in lazily
+            uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP);
+            if (uwt == null)
+                uwt = wt;    // type has no wrappers or prims at all
+            wt.wrapAlt = uwt;
+        }
+        return uwt;
+    }
+
+    /** @param num the index (zero-based) of the desired parameter type
+     *  @return the selected parameter type
+     */
+    public Class<?> parameterType(int num) {
+        return ptypes[num];
+    }
+    /** @return the number of parameter types */
+    public int parameterCount() {
+        return ptypes.length;
+    }
+    /** @return the return type */
+    public Class<?> returnType() {
+        return rtype;
+    }
+
+    /**
+     * Convenience method to present the arguments as a list.
+     * @return the parameter types (as an immutable list)
+     */
+    public List<Class<?>> parameterList() {
+        return Collections.unmodifiableList(Arrays.asList(ptypes));
+    }
+
+    /**
+     * Convenience method to present the arguments as an array.
+     * @return the parameter types (as a fresh copy if necessary)
+     */
+    public Class<?>[] parameterArray() {
+        return ptypes.clone();
+    }
+
+    /**
+     * Compares the specified object with this type for equality.
+     * That is, it returns <tt>true</tt> if and only if the specified object
+     * is also a method type with exactly the same parameters and return type.
+     * @param x object to compare
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object x) {
+        return this == x || x instanceof MethodType && equals((MethodType)x);
+    }
+
+    private boolean equals(MethodType that) {
+        return this.rtype == that.rtype
+            && Arrays.equals(this.ptypes, that.ptypes);
+    }
+
+    /**
+     * Returns the hash code value for this method type.
+     * It is defined to be the same as the hashcode of a List
+     * whose elements are the return type followed by the
+     * parameter types.
+     * @return the hash code value for this method type
+     * @see Object#hashCode()
+     * @see #equals(Object)
+     * @see List#hashCode()
+     */
+    @Override
+    public int hashCode() {
+      int hashCode = 31 + rtype.hashCode();
+      for (Class<?> ptype : ptypes)
+          hashCode = 31*hashCode + ptype.hashCode();
+      return hashCode;
+    }
+
+    /**
+     * The string representation of a method type is a
+     * parenthesis enclosed, comma separated list of type names,
+     * followed immediately by the return type.
+     * <p>
+     * If a type name is array, it the base type followed
+     * by [], rather than the Class.getName of the array type.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("(");
+        for (int i = 0; i < ptypes.length; i++) {
+            if (i > 0)  sb.append(",");
+            putName(sb, ptypes[i]);
+        }
+        sb.append(")");
+        putName(sb, rtype);
+        return sb.toString();
+    }
+
+    static void putName(StringBuilder sb, Class<?> cls) {
+        int brackets = 0;
+        while (cls.isArray()) {
+            cls = cls.getComponentType();
+            brackets++;
+        }
+        String n = cls.getName();
+        /*
+        if (n.startsWith("java.lang.")) {
+            String nb = n.substring("java.lang.".length());
+            if (nb.indexOf('.') < 0)  n = nb;
+        } else if (n.indexOf('.') < 0) {
+            n = "."+n;          // anonymous package
+        }
+        */
+        sb.append(n);
+        while (brackets > 0) {
+            sb.append("[]");
+            brackets--;
+        }
+    }
+
+    /// Queries which have to do with the bytecode architecture
+
+    /** The number of JVM stack slots required to invoke a method
+     * of this type.  Note that (for historic reasons) the JVM requires
+     * a second stack slot to pass long and double arguments.
+     * So this method returns {@link #parameterCount()} plus the
+     * number of long and double parameters (if any).
+     * <p>
+     * This method is included for the benfit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @return the number of JVM stack slots for this type's parameters
+     */
+    public int parameterSlotCount() {
+        return form.parameterSlotCount();
+    }
+
+    /** Number of JVM stack slots which carry all parameters after
+     * the given position, which must be in the range of 0 to
+     * {@code parameterCount} inclusive.  Successive parameters are
+     * more shallowly stacked, and parameters are indexed in the bytecodes
+     * according to their trailing edge.  Thus, to obtain the depth
+     * in the outgoing call stack of parameter {@code N}, obtain
+     * the {@code parameterSlotDepth} of its trailing edge
+     * at position {@code N+1}.
+     * <p>
+     * Parameters of type {@code long} and {@code double} occupy
+     * two stack slots (for historical reasons) and all others occupy one.
+     * Therefore, the number returned is the number of arguments
+     * <em>including</em> and <em>after</em> the given parameter,
+     * <em>plus</em> the number of long or double arguments
+     * at or after after the argument for the given parameter.
+     * <p>
+     * This method is included for the benfit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @param num an index (zero-based, inclusive) within the parameter types
+     * @return the index of the (shallowest) JVM stack slot transmitting the
+     *         given parameter
+     */
+    public int parameterSlotDepth(int num) {
+        if (num < 0 || num > ptypes.length)
+            parameterType(num);  // force a range check
+        return form.parameterToArgSlot(num-1);
+    }
+
+    /** The number of JVM stack slots required to receive a return value
+     * from a method of this type.
+     * If the {@link #returnType() return type} is void, it will be zero,
+     * else if the return type is long or double, it will be two, else one.
+     * <p>
+     * This method is included for the benfit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
+     */
+    public int returnSlotCount() {
+        return form.returnSlotCount();
+    }
+
+    /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+     * Find or create an instance (interned) of the given method type.
+     * Any class or interface name embedded in the signature string
+     * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
+     * on the given loader (or if it is null, on the system class loader).
+     * <p>
+     * Note that it is possible to build method types which cannot be
+     * constructed by this method, because their component types are
+     * not all reachable from a common class loader.
+     * <p>
+     * This method is included for the benfit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @param bytecodeSignature a bytecode-level signature string "(T...)T"
+     * @param loader the class loader in which to look up the types
+     * @return a method type matching the bytecode-level signature
+     * @throws IllegalArgumentException if the string is not well-formed
+     * @throws TypeNotPresentException if a named type cannot be found
+     */
+    public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
+        throws IllegalArgumentException, TypeNotPresentException
+    {
+        List<Class<?>> types = BytecodeSignature.parseMethod(bytecodeSignature, loader);
+        Class<?> rtype = types.remove(types.size() - 1);
+        Class<?>[] ptypes = types.toArray(NO_PTYPES);
+        return makeImpl(rtype, ptypes, true);
+    }
+
+    /**
+     * Create a bytecode signature representation of the type.
+     * Note that this is not a strict inverse of
+     * <p>
+     * This method is included for the benfit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)},
+     * because the latter requires a suitable class loader argument.
+     * @return the bytecode signature representation
+     */
+    public String toBytecodeString() {
+        return BytecodeSignature.unparse(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/MethodTypeForm.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * TO DO:  Temporary shim; remove after refactoring effects are complete in JVM.
+ * @author John Rose
+ */
+import sun.dyn.MethodTypeImpl;
+
+class MethodTypeForm extends MethodTypeImpl {
+
+    MethodTypeForm(MethodType erasedType) {
+        super(erasedType);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/NoAccessException.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,75 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * Thrown to indicate that a caller has attempted to create a method handle
+ * which calls a method to which the caller does not have access.
+ * This unchecked exception is analogous to {@link IllegalAccessException},
+ * which is a checked exception thrown when reflective invocation fails
+ * because of an access check.  With method handles, this same access
+ * checking is performed on behalf of the method handle creator,
+ * at the time of creation.
+ * @author John Rose, JSR 292 EG
+ */
+public class NoAccessException extends RuntimeException {
+    /**
+     * Constructs a {@code NoAccessException} with no detail message.
+     */
+    public NoAccessException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code NoAccessException} with the specified
+     * detail message.
+     *
+     * @param s the detail message
+     */
+    public NoAccessException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a {@code NoAccessException} with the specified cause.
+     *
+     * @param cause the underlying cause of the exception
+     */
+    public NoAccessException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code NoAccessException} with the specified
+     * detail message and cause.
+     *
+     * @param s the detail message
+     * @param cause the underlying cause of the exception
+     */
+    public NoAccessException(String s, Throwable cause) {
+        super(s, cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/WrongMethodTypeException.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,59 @@
+/*
+ * 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 java.dyn;
+
+/**
+ * Thrown to indicate that code has attempted to call a method handle
+ * via the wrong method type.  As with the bytecode representation of
+ * normal Java method calls, method handle calls are strongly typed
+ * to a specific signature associated with a call site.
+ * <p>
+ * This exception may also be thrown when two method handles are
+ * composed, and the system detects that their types cannot be
+ * matched up correctly.  This amounts to an early evaluation
+ * of the type mismatch, at method handle construction time,
+ * instead of when the mismatched method handle is called.
+ *
+ * @author John Rose, JSR 292 EG
+ */
+public class WrongMethodTypeException extends RuntimeException {
+    /**
+     * Constructs a {@code WrongMethodTypeException} with no detail message.
+     */
+    public WrongMethodTypeException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code WrongMethodTypeException} with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public WrongMethodTypeException(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/package-info.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains dynamic language support provided directly by
+ * the Java core class libraries and virtual machine.
+ * @author John Rose, JSR 292 EG
+ */
+
+package java.dyn;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/Access.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,109 @@
+/*
+ * 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 sun.dyn;
+
+import sun.reflect.Reflection;
+
+/**
+ * Access control to this package.
+ * Classes in other packages can attempt to acquire the access token,
+ * but will fail if they are not recognized as friends.
+ * Certain methods in this package, although public, require a non-null
+ * access token in order to proceed; they act like package-private methods.
+ * @author jrose
+ */
+
+public class Access {
+
+    private Access() { }
+
+    /**
+     * The heart of this pattern:  The list of classes which are
+     * permitted to acquire the access token, and become honorary
+     * members of this package.
+     */
+    private static final String[] FRIENDS = {
+        "java.dyn.", "sun.dyn."
+    };
+
+    /**
+     * The following object is NOT public.  That's the point of the pattern.
+     * It is package-private, so that any member of this package
+     * can acquire the access token, and give it away to trusted friends.
+     */
+    static final Access TOKEN = new Access();
+
+    /**
+     * @return Access.TOKEN, if the caller is a friend of this package
+     */
+    public static Access getToken() {
+        Class<?> callc = Reflection.getCallerClass(2);
+        if (isFriend(callc))
+            return TOKEN;
+        else
+            throw new IllegalAccessError("bad caller: " + callc);
+    }
+
+    /** Is the given name the name of a class which could be our friend? */
+    public static boolean isFriendName(String name) {
+        for (String friend : FRIENDS) {
+            if (name.startsWith(friend))
+                return true;
+        }
+        return false;
+    }
+
+    /** Is the given class a friend?  True if {@link #isFriendName},
+     *  and the given class also shares a class loader with us.
+     */
+    public static boolean isFriend(Class<?> c) {
+        return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER;
+    }
+
+    private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader();
+
+    /**
+     * Throw an IllegalAccessError if the caller does not possess
+     * the Access.TOKEN.
+     * @param must be Access.TOKEN
+     */
+    public static void check(Access token) {
+        if (token == null)
+            fail();
+        // else it must be the unique Access.TOKEN
+        assert(token == Access.TOKEN);
+    }
+    private static void fail() {
+        final int CALLER_DEPTH = 3;
+        // 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller
+        Class<?> callc = Reflection.getCallerClass(CALLER_DEPTH);
+        throw new IllegalAccessError("bad caller: " + callc);
+    }
+
+    static {
+        //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/AdapterMethodHandle.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,728 @@
+/*
+ * 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 sun.dyn;
+
+import sun.dyn.util.VerifyType;
+import sun.dyn.util.Wrapper;
+import java.dyn.*;
+import java.util.Arrays;
+import static sun.dyn.MethodHandleNatives.Constants.*;
+import static sun.dyn.MethodHandleImpl.newIllegalArgumentException;
+
+/**
+ * This method handle performs simple conversion or checking of a single argument.
+ * @author jrose
+ */
+public class AdapterMethodHandle extends BoundMethodHandle {
+
+    //MethodHandle vmtarget;   // next AMH or BMH in chain or final DMH
+    //Object       argument;   // parameter to the conversion if needed
+    //int          vmargslot;  // which argument slot is affected
+    private final int conversion;  // the type of conversion: RETYPE_ONLY, etc.
+
+    // Constructors in this class *must* be package scoped or private.
+    private AdapterMethodHandle(MethodHandle target, MethodType newType,
+                long conv, Object convArg) {
+        super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
+        this.conversion = convCode(conv);
+        if (MethodHandleNatives.JVM_SUPPORT) {
+            // JVM might update VM-specific bits of conversion (ignore)
+            MethodHandleNatives.init(this, target, convArgPos(conv));
+        }
+    }
+    private AdapterMethodHandle(MethodHandle target, MethodType newType,
+                long conv) {
+        this(target, newType, conv, null);
+    }
+
+    private static final Access IMPL_TOKEN = Access.getToken();
+
+    // TO DO:  When adapting another MH with a null conversion, clone
+    // the target and change its type, instead of adding another layer.
+
+    /** Can a JVM-level adapter directly implement the proposed
+     *  argument conversions, as if by MethodHandles.convertArguments?
+     */
+    public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
+        // same number of args, of course
+        int len = newType.parameterCount();
+        if (len != oldType.parameterCount())
+            return false;
+
+        // Check return type.  (Not much can be done with it.)
+        Class<?> exp = newType.returnType();
+        Class<?> ret = oldType.returnType();
+        if (!VerifyType.isNullConversion(ret, exp))
+            return false;
+
+        // Check args pairwise.
+        for (int i = 0; i < len; i++) {
+            Class<?> src = newType.parameterType(i); // source type
+            Class<?> dst = oldType.parameterType(i); // destination type
+            if (!canConvertArgument(src, dst))
+                return false;
+        }
+
+        return true;
+    }
+
+    /** Can a JVM-level adapter directly implement the proposed
+     *  argument conversion, as if by MethodHandles.convertArguments?
+     */
+    public static boolean canConvertArgument(Class<?> src, Class<?> dst) {
+        // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
+        // so we don't need to repeat so much decision making.
+        if (VerifyType.isNullConversion(src, dst)) {
+            return true;
+        } else if (src.isPrimitive()) {
+            if (dst.isPrimitive())
+                return canPrimCast(src, dst);
+            else
+                return canBoxArgument(src, dst);
+        } else {
+            if (dst.isPrimitive())
+                return canUnboxArgument(src, dst);
+            else
+                return true;  // any two refs can be interconverted
+        }
+    }
+
+    /**
+     * Create a JVM-level adapter method handle to conform the given method
+     * handle to the similar newType, using only pairwise argument conversions.
+     * For each argument, convert incoming argument to the exact type needed.
+     * Only null conversions are allowed on the return value (until
+     * the JVM supports ricochet adapters).
+     * The argument conversions allowed are casting, unboxing,
+     * integral widening or narrowing, and floating point widening or narrowing.
+     * @param token access check
+     * @param newType required call type
+     * @param target original method handle
+     * @return an adapter to the original handle with the desired new type,
+     *          or the original target if the types are already identical
+     *          or null if the adaptation cannot be made
+     */
+    public static MethodHandle makePairwiseConvert(Access token,
+                MethodType newType, MethodHandle target) {
+        Access.check(token);
+        MethodType oldType = target.type();
+        if (newType == oldType)  return target;
+
+        if (!canPairwiseConvert(newType, oldType))
+            return null;
+        // (after this point, it is an assertion error to fail to convert)
+
+        // Find last non-trivial conversion (if any).
+        int lastConv = newType.parameterCount()-1;
+        while (lastConv >= 0) {
+            Class<?> src = newType.parameterType(lastConv); // source type
+            Class<?> dst = oldType.parameterType(lastConv); // destination type
+            if (VerifyType.isNullConversion(src, dst)) {
+                --lastConv;
+            } else {
+                break;
+            }
+        }
+        // Now build a chain of one or more adapters.
+        MethodHandle adapter = target;
+        MethodType midType = oldType.changeReturnType(newType.returnType());
+        for (int i = 0; i <= lastConv; i++) {
+            Class<?> src = newType.parameterType(i); // source type
+            Class<?> dst = midType.parameterType(i); // destination type
+            if (VerifyType.isNullConversion(src, dst)) {
+                // do nothing: difference is trivial
+                continue;
+            }
+            // Work the current type backward toward the desired caller type:
+            if (i != lastConv) {
+                midType = midType.changeParameterType(i, src);
+            } else {
+                // When doing the last (or only) real conversion,
+                // force all remaining null conversions to happen also.
+                assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
+                midType = newType;
+            }
+
+            // Tricky case analysis follows.
+            // It parallels canConvertArgument() above.
+            if (src.isPrimitive()) {
+                if (dst.isPrimitive()) {
+                    adapter = makePrimCast(token, midType, adapter, i, dst);
+                } else {
+                    adapter = makeBoxArgument(token, midType, adapter, i, dst);
+                }
+            } else {
+                if (dst.isPrimitive()) {
+                    // Caller has boxed a primitive.  Unbox it for the target.
+                    // The box type must correspond exactly to the primitive type.
+                    // This is simpler than the powerful set of widening
+                    // conversions supported by reflect.Method.invoke.
+                    // Those conversions require a big nest of if/then/else logic,
+                    // which we prefer to make a user responsibility.
+                    adapter = makeUnboxArgument(token, midType, adapter, i, dst);
+                } else {
+                    // Simple reference conversion.
+                    // Note:  Do not check for a class hierarchy relation
+                    // between src and dst.  In all cases a 'null' argument
+                    // will pass the cast conversion.
+                    adapter = makeCheckCast(token, midType, adapter, i, dst);
+                }
+            }
+            assert(adapter != null);
+            assert(adapter.type() == midType);
+        }
+        if (adapter.type() != newType) {
+            // Only trivial conversions remain.
+            adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
+            assert(adapter != null);
+            // Actually, that's because there were no non-trivial ones:
+            assert(lastConv == -1);
+        }
+        assert(adapter.type() == newType);
+        return adapter;
+    }
+
+    /**
+     * Create a JVM-level adapter method handle to permute the arguments
+     * of the given method.
+     * @param token access check
+     * @param newType required call type
+     * @param target original method handle
+     * @param argumentMap for each target argument, position of its source in newType
+     * @return an adapter to the original handle with the desired new type,
+     *          or the original target if the types are already identical
+     *          and the permutation is null
+     * @throws IllegalArgumentException if the adaptation cannot be made
+     *          directly by a JVM-level adapter, without help from Java code
+     */
+    public static MethodHandle makePermutation(Access token,
+                MethodType newType, MethodHandle target,
+                int[] argumentMap) {
+        MethodType oldType = target.type();
+        boolean nullPermutation = true;
+        for (int i = 0; i < argumentMap.length; i++) {
+            int pos = argumentMap[i];
+            if (pos != i)
+                nullPermutation = false;
+            if (pos < 0 || pos >= newType.parameterCount()) {
+                argumentMap = new int[0]; break;
+            }
+        }
+        if (argumentMap.length != oldType.parameterCount())
+            throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
+        if (nullPermutation) {
+            MethodHandle res = makePairwiseConvert(token, newType, target);
+            // well, that was easy
+            if (res == null)
+                throw newIllegalArgumentException("cannot convert pairwise: "+newType);
+            return res;
+        }
+
+        // Check return type.  (Not much can be done with it.)
+        Class<?> exp = newType.returnType();
+        Class<?> ret = oldType.returnType();
+        if (!VerifyType.isNullConversion(ret, exp))
+            throw newIllegalArgumentException("bad return conversion for "+newType);
+
+        // See if the argument types match up.
+        for (int i = 0; i < argumentMap.length; i++) {
+            int j = argumentMap[i];
+            Class<?> src = newType.parameterType(j);
+            Class<?> dst = oldType.parameterType(i);
+            if (!VerifyType.isNullConversion(src, dst))
+                throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
+        }
+
+        // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
+        // A workable greedy algorithm is as follows:
+        // Drop unused outgoing arguments (right to left: shallowest first).
+        // Duplicate doubly-used outgoing arguments (left to right: deepest first).
+        // Then the remaining problem is a true argument permutation.
+        // Marshal the outgoing arguments as required from left to right.
+        // That is, find the deepest outgoing stack position that does not yet
+        // have the correct argument value, and correct at least that position
+        // by swapping or rotating in the misplaced value (from a shallower place).
+        // If the misplaced value is followed by one or more consecutive values
+        // (also misplaced)  issue a rotation which brings as many as possible
+        // into position.  Otherwise make progress with either a swap or a
+        // rotation.  Prefer the swap as cheaper, but do not use it if it
+        // breaks a slot pair.  Prefer the rotation over the swap if it would
+        // preserve more consecutive values shallower than the target position.
+        // When more than one rotation will work (because the required value
+        // is already adjacent to the target position), then use a rotation
+        // which moves the old value in the target position adjacent to
+        // one of its consecutive values.  Also, prefer shorter rotation
+        // spans, since they use fewer memory cycles for shuffling.
+
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    private static byte basicType(Class<?> type) {
+        if (type == null)  return T_VOID;
+        switch (Wrapper.forBasicType(type)) {
+            case BOOLEAN:  return T_BOOLEAN;
+            case CHAR:     return T_CHAR;
+            case FLOAT:    return T_FLOAT;
+            case DOUBLE:   return T_DOUBLE;
+            case BYTE:     return T_BYTE;
+            case SHORT:    return T_SHORT;
+            case INT:      return T_INT;
+            case LONG:     return T_LONG;
+            case OBJECT:   return T_OBJECT;
+            case VOID:     return T_VOID;
+        }
+        return 99; // T_ILLEGAL or some such
+    }
+
+    /** Number of stack slots for the given type.
+     *  Two for T_DOUBLE and T_FLOAT, one for the rest.
+     */
+    private static int type2size(int type) {
+        assert(type >= T_BOOLEAN && type <= T_OBJECT);
+        return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
+    }
+
+    /** Construct an adapter conversion descriptor for a single-argument conversion. */
+    private static long makeConv(int convOp, int argnum, int src, int dest) {
+        assert(src  == (src  & 0xF));
+        assert(dest == (dest & 0xF));
+        assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF);
+        long stackMove = type2size(dest) - type2size(src);
+        return ((long) argnum << 32 |
+                (long) convOp << CONV_OP_SHIFT |
+                (int)  src    << CONV_SRC_TYPE_SHIFT |
+                (int)  dest   << CONV_DEST_TYPE_SHIFT |
+                stackMove     << CONV_STACK_MOVE_SHIFT
+                );
+    }
+    private static long makeConv(int convOp, int argnum, int stackMove) {
+        assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS);
+        byte src = 0, dest = 0;
+        if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
+            src = dest = T_OBJECT;
+        return ((long) argnum << 32 |
+                (long) convOp << CONV_OP_SHIFT |
+                (int)  src    << CONV_SRC_TYPE_SHIFT |
+                (int)  dest   << CONV_DEST_TYPE_SHIFT |
+                stackMove     << CONV_STACK_MOVE_SHIFT
+                );
+    }
+    private static long makeConv(int convOp) {
+        assert(convOp == OP_RETYPE_ONLY);
+        return (long) convOp << CONV_OP_SHIFT;   // stackMove, src, dst, argnum all zero
+    }
+    private static int convCode(long conv) {
+        return (int)conv;
+    }
+    private static int convArgPos(long conv) {
+        return (int)(conv >>> 32);
+    }
+    private static boolean convOpSupported(int convOp) {
+        assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
+        return ((1<<convOp) & CONV_OP_IMPLEMENTED_MASK) != 0;
+    }
+
+    /** One of OP_RETYPE_ONLY, etc. */
+    int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
+
+    @Override
+    public String toString() {
+        return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]");
+    }
+
+    private static MethodHandle nonAdapter(MethodHandle mh) {
+        return (MethodHandle)
+            MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE);
+    }
+
+    /* Return one plus the position of the first non-trivial difference
+     * between the given types.  This is not a symmetric operation;
+     * we are considering adapting the targetType to adapterType.
+     * Trivial differences are those which could be ignored by the JVM
+     * without subverting the verifier.  Otherwise, adaptable differences
+     * are ones for which we could create an adapter to make the type change.
+     * Return zero if there are no differences (other than trivial ones).
+     * Return 1+N if N is the only adaptable argument difference.
+     * Return the -2-N where N is the first of several adaptable
+     * argument differences.
+     * Return -1 if there there are differences which are not adaptable.
+     */
+    private static int diffTypes(MethodType adapterType,
+                                 MethodType targetType,
+                                 boolean raw) {
+        int diff;
+        diff = diffReturnTypes(adapterType, targetType, raw);
+        if (diff != 0)  return diff;
+        int nargs = adapterType.parameterCount();
+        if (nargs != targetType.parameterCount())
+            return -1;
+        diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
+        //System.out.println("diff "+adapterType);
+        //System.out.println("  "+diff+" "+targetType);
+        return diff;
+    }
+    private static int diffReturnTypes(MethodType adapterType,
+                                       MethodType targetType,
+                                       boolean raw) {
+        Class<?> src = targetType.returnType();
+        Class<?> dst = adapterType.returnType();
+        if ((!raw
+             ? VerifyType.canPassUnchecked(src, dst)
+             : VerifyType.canPassRaw(src, dst)
+             ) > 0)
+            return 0;  // no significant difference
+        if (raw && !src.isPrimitive() && !dst.isPrimitive())
+            return 0;  // can force a reference return (very carefully!)
+        //if (false)  return 1;  // never adaptable!
+        return -1;  // some significant difference
+    }
+    private static int diffParamTypes(MethodType adapterType, int tstart,
+                                      MethodType targetType, int astart,
+                                      int nargs, boolean raw) {
+        assert(nargs >= 0);
+        int res = 0;
+        for (int i = 0; i < nargs; i++) {
+            Class<?> src  = adapterType.parameterType(tstart+i);
+            Class<?> dest = targetType.parameterType(astart+i);
+            if ((!raw
+                 ? VerifyType.canPassUnchecked(src, dest)
+                 : VerifyType.canPassRaw(src, dest)
+                ) <= 0) {
+                // found a difference; is it the only one so far?
+                if (res != 0)
+                    return -1-res; // return -2-i for prev. i
+                res = 1+i;
+            }
+        }
+        return res;
+    }
+
+    /** Can a retyping adapter (alone) validly convert the target to newType? */
+    public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
+        return canRetypeOnly(newType, targetType, false);
+    }
+    /** Can a retyping adapter (alone) convert the target to newType?
+     *  It is allowed to widen subword types and void to int, to make bitwise
+     *  conversions between float/int and double/long, and to perform unchecked
+     *  reference conversions on return.  This last feature requires that the
+     *  caller be trusted, and perform explicit cast conversions on return values.
+     */
+    static boolean canRawRetypeOnly(MethodType newType, MethodType targetType) {
+        return canRetypeOnly(newType, targetType, true);
+    }
+    static boolean canRetypeOnly(MethodType newType, MethodType targetType, boolean raw) {
+        if (!convOpSupported(OP_RETYPE_ONLY))  return false;
+        int diff = diffTypes(newType, targetType, raw);
+        // %%% This assert is too strong.  Factor diff into VerifyType and reconcile.
+        assert((diff == 0) == VerifyType.isNullConversion(newType, targetType));
+        return diff == 0;
+    }
+
+    /** Factory method:  Performs no conversions; simply retypes the adapter.
+     *  Allows unchecked argument conversions pairwise, if they are safe.
+     *  Returns null if not possible.
+     */
+    public static MethodHandle makeRetypeOnly(Access token,
+                MethodType newType, MethodHandle target) {
+        return makeRetypeOnly(token, newType, target, false);
+    }
+    public static MethodHandle makeRawRetypeOnly(Access token,
+                MethodType newType, MethodHandle target) {
+        return makeRetypeOnly(token, newType, target, true);
+    }
+    static MethodHandle makeRetypeOnly(Access token,
+                MethodType newType, MethodHandle target, boolean raw) {
+        Access.check(token);
+        if (!canRetypeOnly(newType, target.type(), raw))
+            return null;
+        // TO DO:  clone the target guy, whatever he is, with new type.
+        return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY));
+    }
+
+    /** Can a checkcast adapter validly convert the target to newType?
+     *  The JVM supports all kind of reference casts, even silly ones.
+     */
+    public static boolean canCheckCast(MethodType newType, MethodType targetType,
+                int arg, Class<?> castType) {
+        if (!convOpSupported(OP_CHECK_CAST))  return false;
+        Class<?> src = newType.parameterType(arg);
+        Class<?> dst = targetType.parameterType(arg);
+        if (!canCheckCast(src, castType)
+                || !VerifyType.isNullConversion(castType, dst))
+            return false;
+        int diff = diffTypes(newType, targetType, false);
+        return (diff == arg+1);  // arg is sole non-trivial diff
+    }
+    /** Can an primitive conversion adapter validly convert src to dst? */
+    public static boolean canCheckCast(Class<?> src, Class<?> dst) {
+        return (!src.isPrimitive() && !dst.isPrimitive());
+    }
+
+    /** Factory method:  Forces a cast at the given argument.
+     *  The castType is the target of the cast, and can be any type
+     *  with a null conversion to the corresponding target parameter.
+     *  Return null if this cannot be done.
+     */
+    public static MethodHandle makeCheckCast(Access token,
+                MethodType newType, MethodHandle target,
+                int arg, Class<?> castType) {
+        Access.check(token);
+        if (!canCheckCast(newType, target.type(), arg, castType))
+            return null;
+        long conv = makeConv(OP_CHECK_CAST, arg, 0);
+        return new AdapterMethodHandle(target, newType, conv, castType);
+    }
+
+    /** Can an primitive conversion adapter validly convert the target to newType?
+     *  The JVM currently supports all conversions except those between
+     *  floating and integral types.
+     */
+    public static boolean canPrimCast(MethodType newType, MethodType targetType,
+                int arg, Class<?> convType) {
+        if (!convOpSupported(OP_PRIM_TO_PRIM))  return false;
+        Class<?> src = newType.parameterType(arg);
+        Class<?> dst = targetType.parameterType(arg);
+        if (!canPrimCast(src, convType)
+                || !VerifyType.isNullConversion(convType, dst))
+            return false;
+        int diff = diffTypes(newType, targetType, false);
+        return (diff == arg+1);  // arg is sole non-trivial diff
+    }
+    /** Can an primitive conversion adapter validly convert src to dst? */
+    public static boolean canPrimCast(Class<?> src, Class<?> dst) {
+        if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
+            return false;
+        } else if (Wrapper.forPrimitiveType(dst).isFloating()) {
+            // both must be floating types
+            return Wrapper.forPrimitiveType(src).isFloating();
+        } else {
+            // both are integral, and all combinations work fine
+            assert(Wrapper.forPrimitiveType(src).isIntegral() &&
+                   Wrapper.forPrimitiveType(dst).isIntegral());
+            return true;
+        }
+    }
+
+    /** Factory method:  Truncate the given argument with zero or sign extension,
+     *  and/or convert between single and doubleword versions of integer or float.
+     *  The convType is the target of the conversion, and can be any type
+     *  with a null conversion to the corresponding target parameter.
+     *  Return null if this cannot be done.
+     */
+    public static MethodHandle makePrimCast(Access token,
+                MethodType newType, MethodHandle target,
+                int arg, Class<?> convType) {
+        Access.check(token);
+        MethodType oldType = target.type();
+        Class<?> src = newType.parameterType(arg);
+        Class<?> dst = oldType.parameterType(arg);
+        if (!canPrimCast(newType, oldType, arg, convType))
+            return null;
+        long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
+        return new AdapterMethodHandle(target, newType, conv);
+    }
+
+    /** Can an unboxing conversion validly convert src to dst?
+     *  The JVM currently supports all kinds of casting and unboxing.
+     *  The convType is the unboxed type; it can be either a primitive or wrapper.
+     */
+    public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
+                int arg, Class<?> convType) {
+        if (!convOpSupported(OP_REF_TO_PRIM))  return false;
+        Class<?> src = newType.parameterType(arg);
+        Class<?> dst = targetType.parameterType(arg);
+        Class<?> boxType = Wrapper.asWrapperType(convType);
+        convType = Wrapper.asPrimitiveType(convType);
+        if (!canCheckCast(src, boxType)
+                || boxType == convType
+                || !VerifyType.isNullConversion(convType, dst))
+            return false;
+        int diff = diffTypes(newType, targetType, false);
+        return (diff == arg+1);  // arg is sole non-trivial diff
+    }
+    /** Can an primitive unboxing adapter validly convert src to dst? */
+    public static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
+        return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
+    }
+
+    /** Factory method:  Unbox the given argument.
+     *  Return null if this cannot be done.
+     */
+    public static MethodHandle makeUnboxArgument(Access token,
+                MethodType newType, MethodHandle target,
+                int arg, Class<?> convType) {
+        MethodType oldType = target.type();
+        Class<?> src = newType.parameterType(arg);
+        Class<?> dst = oldType.parameterType(arg);
+        Class<?> boxType = Wrapper.asWrapperType(convType);
+        Class<?> primType = Wrapper.asPrimitiveType(convType);
+        if (!canUnboxArgument(newType, oldType, arg, convType))
+            return null;
+        MethodType castDone = newType;
+        if (!VerifyType.isNullConversion(src, boxType))
+            castDone = newType.changeParameterType(arg, boxType);
+        long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
+        MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
+        if (castDone == newType)
+            return adapter;
+        return makeCheckCast(token, newType, adapter, arg, boxType);
+    }
+
+    /** Can an primitive boxing adapter validly convert src to dst? */
+    public static boolean canBoxArgument(Class<?> src, Class<?> dst) {
+        if (!convOpSupported(OP_PRIM_TO_REF))  return false;
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    /** Factory method:  Unbox the given argument.
+     *  Return null if this cannot be done.
+     */
+    public static MethodHandle makeBoxArgument(Access token,
+                MethodType newType, MethodHandle target,
+                int arg, Class<?> convType) {
+        // this is difficult to do in the JVM because it must GC
+        return null;
+    }
+
+    // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments
+
+    /** Can an adapter simply drop arguments to convert the target to newType? */
+    public static boolean canDropArguments(MethodType newType, MethodType targetType,
+                int dropArgPos, int dropArgCount) {
+        if (dropArgCount == 0)
+            return canRetypeOnly(newType, targetType);
+        if (!convOpSupported(OP_DROP_ARGS))  return false;
+        if (diffReturnTypes(newType, targetType, false) != 0)
+            return false;
+        int nptypes = newType.parameterCount();
+        // parameter types must be the same up to the drop point
+        if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
+            return false;
+        int afterPos = dropArgPos + dropArgCount;
+        int afterCount = nptypes - afterPos;
+        if (dropArgPos < 0 || dropArgPos >= nptypes ||
+            dropArgCount < 1 || afterPos > nptypes ||
+            targetType.parameterCount() != nptypes - dropArgCount)
+            return false;
+        // parameter types after the drop point must also be the same
+        if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
+            return false;
+        return true;
+    }
+
+    /** Factory method:  Drop selected arguments.
+     *  Allow unchecked retyping of remaining arguments, pairwise.
+     *  Return null if this is not possible.
+     */
+    public static MethodHandle makeDropArguments(Access token,
+                MethodType newType, MethodHandle target,
+                int dropArgPos, int dropArgCount) {
+        Access.check(token);
+        if (dropArgCount == 0)
+            return makeRetypeOnly(IMPL_TOKEN, newType, target);
+        MethodType mt = target.type();
+        int argCount  = mt.parameterCount();
+        if (!canDropArguments(newType, mt, dropArgPos, dropArgCount))
+            return null;
+        int dropSlotCount, dropSlotPos;
+        if (dropArgCount >= argCount) {
+            assert(dropArgPos == argCount-1);
+            dropSlotPos = 0;
+            dropSlotCount = mt.parameterSlotCount();
+        } else {
+            // arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ]
+            int lastDroppedArg = dropArgPos + dropArgCount - 1;
+            int lastKeptArg    = dropArgPos - 1;  // might be -1, which is OK
+            dropSlotPos      = mt.parameterSlotDepth(1+lastDroppedArg);
+            int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg);
+            dropSlotCount = lastKeptSlot - dropSlotPos;
+            assert(dropSlotCount >= dropArgCount);
+        }
+        long conv = makeConv(OP_DROP_ARGS, dropArgPos, +dropSlotCount);
+        return new AdapterMethodHandle(target, newType, dropSlotCount, conv);
+    }
+
+    /** Can an adapter spread an argument to convert the target to newType? */
+    public static boolean canSpreadArguments(MethodType newType, MethodType targetType,
+                Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
+        if (!convOpSupported(OP_SPREAD_ARGS))  return false;
+        if (diffReturnTypes(newType, targetType, false) != 0)
+            return false;
+        int nptypes = newType.parameterCount();
+        // parameter types must be the same up to the spread point
+        if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
+            return false;
+        int afterPos = spreadArgPos + spreadArgCount;
+        int afterCount = nptypes - afterPos;
+        if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
+            spreadArgCount < 0 ||
+            targetType.parameterCount() != nptypes - 1 + spreadArgCount)
+            return false;
+        // parameter types after the spread point must also be the same
+        if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
+            return false;
+        // match the array element type to the spread arg types
+        Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos);
+        if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
+            return false;
+        for (int i = 0; i < spreadArgCount; i++) {
+            Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i);
+            Class<?> dst = targetType.parameterType(spreadArgPos + i);
+            if (src == null || !VerifyType.isNullConversion(src, dst))
+                return false;
+        }
+        return true;
+    }
+
+    /** Factory method:  Spread selected argument. */
+    public static MethodHandle makeSpreadArguments(Access token,
+                MethodType newType, MethodHandle target,
+                Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
+        Access.check(token);
+        MethodType mt = target.type();
+        int argCount  = mt.parameterCount();
+        if (!canSpreadArguments(newType, mt, spreadArgType, spreadArgPos, spreadArgCount))
+            return null;
+        int spreadSlotCount, spreadSlotPos;
+        if (spreadArgCount >= argCount) {
+            assert(spreadArgPos == argCount-1);
+            spreadSlotPos = 0;
+            spreadSlotCount = mt.parameterSlotCount();
+        } else {
+            // arglist: [0: keep... | dpos: spread... | dpos+dcount: keep... ]
+            int lastSpreadArg = spreadArgPos + spreadArgCount - 1;
+            int lastKeptArg   = spreadArgPos - 1;  // might be -1, which is OK
+            spreadSlotPos     = mt.parameterSlotDepth(1+lastSpreadArg);
+            int lastKeptSlot  = mt.parameterSlotDepth(1+lastKeptArg);
+            spreadSlotCount = lastKeptSlot - spreadSlotPos;
+            assert(spreadSlotCount >= spreadArgCount);
+        }
+        long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, spreadSlotCount);
+        return new AdapterMethodHandle(target, newType, conv, spreadArgType);
+    }
+
+    // TO DO: makeCollectArguments, makeFlyby, makeRicochet
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/BoundMethodHandle.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,180 @@
+/*
+ * 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 sun.dyn;
+
+import sun.dyn.util.VerifyType;
+import sun.dyn.util.Wrapper;
+import java.dyn.*;
+
+/**
+ * The flavor of method handle which emulates an invoke instruction
+ * on a predetermined argument.  The JVM dispatches to the correct method
+ * when the handle is created, not when it is invoked.
+ * @author jrose
+ */
+public class BoundMethodHandle extends MethodHandle  {
+    //MethodHandle vmtarget;           // next BMH or final DMH or methodOop
+    private final Object argument;     // argument to insert
+    private final int    vmargslot;    // position at which it is inserted
+
+    // Constructors in this class *must* be package scoped or private.
+
+    /** Bind a direct MH to its receiver (or first ref. argument).
+     *  The JVM will pre-dispatch the MH if it is not already static.
+     */
+    BoundMethodHandle(DirectMethodHandle mh, Object argument) {
+        super(Access.TOKEN, mh.type().dropParameterType(0));
+        // check the type now, once for all:
+        this.argument = checkReferenceArgument(argument, mh, 0);
+        this.vmargslot = this.type().parameterSlotCount();
+        if (MethodHandleNatives.JVM_SUPPORT) {
+            this.vmtarget = null;  // maybe updated by JVM
+            MethodHandleNatives.init(this, mh, 0);
+        } else {
+            this.vmtarget = mh;
+        }
+     }
+
+    private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2;
+
+    /** Insert an argument into an arbitrary method handle.
+     *  If argnum is zero, inserts the first argument, etc.
+     *  The argument type must be a reference.
+     */
+    BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
+        this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG);
+    }
+
+    /** Insert an argument into an arbitrary method handle.
+     *  If argnum is zero, inserts the first argument, etc.
+     */
+    BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) {
+        super(Access.TOKEN, mh.type().dropParameterType(argnum));
+        if (whichArg == PRIM_ARG)
+            this.argument = bindPrimitiveArgument(argument, mh, argnum);
+        else {
+            if (whichArg == SELF_ARG)  argument = this;
+            this.argument = checkReferenceArgument(argument, mh, argnum);
+        }
+        this.vmargslot = this.type().parameterSlotDepth(argnum);
+        if (MethodHandleNatives.JVM_SUPPORT) {
+            this.vmtarget = null;  // maybe updated by JVM
+            MethodHandleNatives.init(this, mh, argnum);
+        } else {
+            this.vmtarget = mh;
+        }
+    }
+
+    /** For the AdapterMethodHandle subclass.
+     */
+    BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
+        super(Access.TOKEN, type);
+        this.argument = argument;
+        this.vmargslot = vmargslot;
+        assert(this.getClass() == AdapterMethodHandle.class);
+    }
+
+    /** Initialize the current object as a method handle, binding it
+     *  as the {@code argnum}th argument of the method handle {@code entryPoint}.
+     *  The invocation type of the resulting method handle will be the
+     *  same as {@code entryPoint},  except that the {@code argnum}th argument
+     *  type will be dropped.
+     */
+    public BoundMethodHandle(MethodHandle entryPoint, int argnum) {
+        this(entryPoint, null, argnum, SELF_ARG);
+
+        // Note:  If the conversion fails, perhaps because of a bad entryPoint,
+        // the MethodHandle.type field will not be filled in, and therefore
+        // no MH.invoke call will ever succeed.  The caller may retain a pointer
+        // to the broken method handle, but no harm can be done with it.
+    }
+
+    /** Initialize the current object as a method handle, binding it
+     *  as the first argument of the method handle {@code entryPoint}.
+     *  The invocation type of the resulting method handle will be the
+     *  same as {@code entryPoint},  except that the first argument
+     *  type will be dropped.
+     */
+    public BoundMethodHandle(MethodHandle entryPoint) {
+        this(entryPoint, null, 0, SELF_ARG);
+    }
+
+    /** Make sure the given {@code argument} can be used as {@code argnum}-th
+     *  parameter of the given method handle {@code mh}, which must be a reference.
+     *  <p>
+     *  If this fails, throw a suitable {@code WrongMethodTypeException},
+     *  which will prevent the creation of an illegally typed bound
+     *  method handle.
+     */
+    final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
+        Class<?> ptype = mh.type().parameterType(argnum);
+        if (ptype.isPrimitive()) {
+            // fail
+        } else if (argument == null) {
+            return null;
+        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
+            return argument;
+        }
+        throw badBoundArgumentException(argument, mh, argnum);
+    }
+
+    /** Make sure the given {@code argument} can be used as {@code argnum}-th
+     *  parameter of the given method handle {@code mh}, which must be a primitive.
+     *  <p>
+     *  If this fails, throw a suitable {@code WrongMethodTypeException},
+     *  which will prevent the creation of an illegally typed bound
+     *  method handle.
+     */
+    final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
+        Class<?> ptype = mh.type().parameterType(argnum);
+        Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
+        Object   zero  = wrap.zero();
+        if (zero == null) {
+            // fail
+        } else if (argument == null) {
+            if (ptype != int.class && wrap.isSubwordOrInt())
+                return Integer.valueOf(0);
+            else
+                return zero;
+        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
+            if (ptype != int.class && wrap.isSubwordOrInt())
+                return Wrapper.INT.wrap(argument);
+            else
+                return argument;
+        }
+        throw badBoundArgumentException(argument, mh, argnum);
+    }
+
+    final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
+        String atype = (argument == null) ? "null" : argument.getClass().toString();
+        return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
+    }
+
+    @Override
+    public String toString() {
+        return "Bound[" + super.toString() + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/CallSiteImpl.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,70 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.*;
+
+/**
+ * The CallSite privately created by the JVM at every invokedynamic instruction.
+ * @author jrose
+ */
+class CallSiteImpl extends CallSite {
+    // Fields used only by the JVM.  Do not use or change.
+    private Object vmmethod;
+
+    // Values supplied by the JVM:
+    int callerMID, callerBCI;
+
+    private CallSiteImpl(Class<?> caller, String name, MethodType type) {
+        super(caller, name, type);
+    }
+
+    @Override
+    public void setTarget(MethodHandle mh) {
+        checkTarget(mh);
+        if (MethodHandleNatives.JVM_SUPPORT)
+            MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
+        else
+            super.setTarget(mh);
+    }
+
+    private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
+            MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite",
+                MethodType.make(void.class, CallSite.class, int.class, int.class));
+
+    // this is the up-call from the JVM:
+    static CallSite makeSite(Class<?> caller, String name, MethodType type,
+                             int callerMID, int callerBCI) {
+        MethodHandle bsm = Linkage.getBootstrapMethod(caller);
+        if (bsm == null)
+            throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller);
+        CallSite site = bsm.<CallSite>invoke(caller, name, type);
+        if (site == null)
+            throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
+        PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI);
+        return site;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/DirectMethodHandle.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,56 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.*;
+import static sun.dyn.MethodHandleNatives.Constants.*;
+
+/**
+ * The flavor of method handle which emulates invokespecial or invokestatic.
+ * @author jrose
+ */
+class DirectMethodHandle extends MethodHandle {
+    //inherited oop    vmtarget;    // methodOop or virtual class/interface oop
+    private final int  vmindex;     // method index within class or interface
+    { vmindex = VM_INDEX_UNINITIALIZED; }  // JVM may change this
+
+    // Constructors in this class *must* be package scoped or private.
+    DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> lookupClass) {
+        super(Access.TOKEN, mtype);
+
+        assert(m.isMethod() || !doDispatch && m.isConstructor());
+        if (!m.isResolved())
+            throw new InternalError();
+
+        // Null check and replace privilege token (as passed to JVM) with null.
+        if (lookupClass.equals(Access.class))  lookupClass = null;
+        MethodHandleNatives.init(this, (Object) m, doDispatch, lookupClass);
+    }
+
+    boolean isValid() {
+        return (vmindex != VM_INDEX_UNINITIALIZED);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/FilterGeneric.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,338 @@
+/*
+ * 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 Sf, tifth 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 sun.dyn;
+
+import java.dyn.JavaMethodHandle;
+import java.dyn.MethodHandle;
+import java.dyn.MethodType;
+import java.dyn.NoAccessException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * "Flyby adapters" which apply arbitrary conversions to arguments
+ * on the way to a ultimate target.
+ * For simplicity, these are all generically typed.
+ * @author jrose
+ */
+class FilterGeneric {
+    // type for the outgoing call (will be generic)
+    private final MethodType targetType;
+    // position of (first) argument to participate in filtering
+    private final short argumentPosition;
+    // number of arguments to participate in filtering
+    private final short argumentCount;
+    // how the result interacts with the filtered arguments: Prepend, Append, Replace, Discard
+    private final char replaceMode;
+    // prototype adapter (clone and customize for each new target & conversion!)
+    private final Adapter adapter;
+    // entry point for adapter (Adapter mh, a...) => ...
+    private final MethodHandle entryPoint;
+    // more of them (loosely cached)
+    private FilterGeneric variations;
+
+    /** Compute and cache information common to all unboxing adapters
+     *  that can call out to targets of the erasure-family of the given erased type.
+     */
+    // TO DO: Make this private.
+    FilterGeneric(MethodType targetType, short argumentPosition, short argumentCount, char replaceMode) {
+        if (argumentCount == 0) {
+            if (replaceMode == 'P' || replaceMode == 'A')  replaceMode = 'R';
+            if (replaceMode == 'I')  argumentPosition = 0;
+        }
+        this.targetType = targetType;
+        this.argumentPosition = argumentPosition;
+        this.argumentCount = argumentCount;
+        this.replaceMode = replaceMode;
+        validate(targetType, argumentPosition, argumentCount, replaceMode);
+        Adapter ad = findAdapter(targetType, argumentPosition, argumentCount, replaceMode, filterType());
+        if (ad == null)
+            ad = buildAdapterFromBytecodes(targetType, argumentPosition, argumentCount, replaceMode, filterType());
+        this.adapter = ad;
+        this.entryPoint = ad.prototypeEntryPoint();
+    }
+
+    Adapter makeInstance(MethodHandle filter, MethodHandle target) {
+        return adapter.makeInstance(entryPoint, filter, target);
+    }
+
+    /** Build an adapter of the given generic type, which invokes typedTarget
+     *  on the incoming arguments, after unboxing as necessary.
+     *  The return value is boxed if necessary.
+     * @param genericType  the required type of the result
+     * @param typedTarget the target
+     * @return an adapter method handle
+     */
+    public static MethodHandle make(MethodHandle target, int pos, MethodHandle filter) {
+        return FilterGeneric.of(target.type(), (short)pos, (short)1, 'R').makeInstance(filter, target);
+    }
+
+    /** Return the adapter information for this type's erasure. */
+    static FilterGeneric of(MethodType type, short ap, short ac, char mode) {
+        if (type.generic() != type)
+            throw new IllegalArgumentException("must be generic: "+type);
+        validate(type, ap, ac, mode);
+        MethodTypeImpl form = MethodTypeImpl.of(type);
+        FilterGeneric filterGen = form.filterGeneric;
+        if (filterGen == null)
+            form.filterGeneric = filterGen = new FilterGeneric(type, (short)0, (short)1, 'R');
+        return find(filterGen, ap, ac, mode);
+    }
+
+    static FilterGeneric find(FilterGeneric gen, short ap, short ac, char mode) {
+        for (;;) {
+            if (gen.argumentPosition == ap &&
+                gen.argumentCount == ac &&
+                gen.replaceMode == mode) {
+                return gen;
+            }
+            FilterGeneric gen2 = gen.variations;
+            if (gen2 == null)  break;
+            gen = gen2;
+        }
+        FilterGeneric gen2 = new FilterGeneric(gen.targetType, ap, ac, mode);
+        gen.variations = gen2;  // OK if this smashes another cached chain
+        return gen2;
+    }
+
+    private static void validate(MethodType type, short ap, short ac, char mode) {
+        int endpos = ap + ac;
+        switch (mode) {
+            case 'P': case 'A': case 'R': case 'D':
+                if (ap >= 0 && ac >= 0 &&
+                        endpos >= 0 && endpos <= type.parameterCount())
+                    return;
+            default:
+                throw new InternalError("configuration "+patternName(ap, ac, mode));
+        }
+    }
+
+    public String toString() {
+        return "FilterGeneric/"+patternName()+targetType;
+    }
+
+    String patternName() {
+        return patternName(argumentPosition, argumentCount, replaceMode);
+    }
+
+    static String patternName(short ap, short ac, char mode) {
+        return ""+mode+ap+(ac>1?"_"+ac:"");
+    }
+
+    Class<?> filterType() {
+        return Object.class;  // result of filter operation; an uninteresting type
+    }
+
+    static MethodType targetType(MethodType entryType, short ap, short ac, char mode,
+                                 Class<?> arg) {
+        MethodType type = entryType;
+        int pos = ap;
+        switch (mode) {
+            case 'A':
+                pos += ac;
+            case 'P':
+                type = type.insertParameterType(pos, arg);
+                break;
+            case 'I':
+                for (int i = 1; i < ac; i++)
+                    type = type.dropParameterType(pos);
+                assert(type.parameterType(pos) == arg);
+                break;
+            case 'D':
+                break;
+        }
+        return type;
+    }
+
+    static MethodType entryType(MethodType targetType, short ap, short ac, char mode,
+                                Class<?> arg) {
+        MethodType type = targetType;
+        int pos = ap;
+        switch (mode) {
+            case 'A':
+                pos += ac;
+            case 'P':
+                type = type.dropParameterType(pos);
+                break;
+            case 'I':
+                for (int i = 1; i < ac; i++)
+                    type = type.insertParameterType(pos, arg);
+                assert(type.parameterType(pos) == arg);
+                break;
+            case 'D':
+                break;
+        }
+        return type;
+    }
+
+    /* Create an adapter that handles spreading calls for the given type. */
+    static Adapter findAdapter(MethodType targetType, short ap, short ac, char mode, Class<?> arg) {
+        MethodType entryType = entryType(targetType, ap, ac, mode, arg);
+        int argc = targetType.parameterCount();
+        String pname = patternName(ap, ac, mode);
+        String cname0 = "F"+argc;
+        String cname1 = "F"+argc+mode;
+        String cname2 = "F"+argc+pname;
+        String[] cnames = { cname0, cname1, cname1+"X", cname2 };
+        String iname = "invoke_"+pname;
+        // e.g., F5R; invoke_R3
+        for (String cname : cnames) {
+            Class<? extends Adapter> acls = Adapter.findSubClass(cname);
+            if (acls == null)  continue;
+            // see if it has the required invoke method
+            MethodHandle entryPoint = null;
+            try {
+                entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+            } catch (NoAccessException ex) {
+            }
+            if (entryPoint == null)  continue;
+            Constructor<? extends Adapter> ctor = null;
+            try {
+                ctor = acls.getDeclaredConstructor(MethodHandle.class);
+            } catch (NoSuchMethodException ex) {
+            } catch (SecurityException ex) {
+            }
+            if (ctor == null)  continue;
+            try {
+                // Produce an instance configured as a prototype.
+                return ctor.newInstance(entryPoint);
+            } catch (IllegalArgumentException ex) {
+            } catch (InvocationTargetException ex) {
+            } catch (InstantiationException ex) {
+            } catch (IllegalAccessException ex) {
+            }
+        }
+        return null;
+    }
+
+    static Adapter buildAdapterFromBytecodes(MethodType targetType, short ap, short ac, char mode, Class<?> arg) {
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    /**
+     * This adapter takes some untyped arguments, and returns an untyped result.
+     * Internally, it applies the invoker to the target, which causes the
+     * objects to be unboxed; the result is a raw type in L/I/J/F/D.
+     * This result is passed to convert, which is responsible for
+     * converting the raw result into a boxed object.
+     * The invoker is kept separate from the target because it can be
+     * generated once per type erasure family, and reused across adapters.
+     */
+    static abstract class Adapter extends JavaMethodHandle {
+        protected final MethodHandle filter;
+        protected final MethodHandle target;
+
+        protected boolean isPrototype() { return target == null; }
+        protected Adapter(MethodHandle entryPoint) {
+            this(entryPoint, entryPoint, null);
+            assert(isPrototype());
+        }
+        protected MethodHandle prototypeEntryPoint() {
+            if (!isPrototype())  throw new InternalError();
+            return filter;
+        }
+
+        protected Adapter(MethodHandle entryPoint,
+                          MethodHandle filter, MethodHandle target) {
+            super(entryPoint);
+            this.filter = filter;
+            this.target = target;
+        }
+
+        /** Make a copy of self, with new fields. */
+        protected abstract Adapter makeInstance(MethodHandle entryPoint,
+                MethodHandle filter, MethodHandle target);
+        // { return new ThisType(entryPoint, filter, target); }
+
+        static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$"
+        static {
+            String aname = Adapter.class.getName();
+            String sname = Adapter.class.getSimpleName();
+            if (!aname.endsWith(sname))  throw new InternalError();
+            CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
+        }
+        /** Find a sibing class of Adapter. */
+        static Class<? extends Adapter> findSubClass(String name) {
+            String cname = Adapter.CLASS_PREFIX + name;
+            try {
+                return Class.forName(cname).asSubclass(Adapter.class);
+            } catch (ClassNotFoundException ex) {
+                return null;
+            } catch (ClassCastException ex) {
+                return null;
+            }
+        }
+    }
+
+    //* generated classes follow this pattern:
+    static class F1RX extends Adapter {
+        protected F1RX(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected F1RX(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { super(e, f, t); }
+        protected F1RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { return new F1RX(e, f, t); }
+        protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
+        protected Object target(Object a0) { return target.<Object>invoke(a0); }
+        protected Object invoke_R0(Object a0) { return target(filter(a0)); }
+    }
+    static class F2RX extends Adapter {
+        protected F2RX(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected F2RX(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { super(e, f, t); }
+        protected F2RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { return new F2RX(e, f, t); }
+        protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
+        protected Object target(Object a0, Object a1) { return target.<Object>invoke(a0, a1); }
+        protected Object invoke_R0(Object a0, Object a1) { return target(filter(a0), a1); }
+        protected Object invoke_R1(Object a0, Object a1) { return target(a0, filter(a1)); }
+    }
+    static class F3RX extends Adapter {
+        protected F3RX(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected F3RX(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { super(e, f, t); }
+        protected F3RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { return new F3RX(e, f, t); }
+        protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
+        protected Object target(Object a0, Object a1, Object a2) { return target.<Object>invoke(a0, a1, a2); }
+        protected Object invoke_R0(Object a0, Object a1, Object a2) { return target(filter(a0), a1, a2); }
+        protected Object invoke_R1(Object a0, Object a1, Object a2) { return target(a0, filter(a1), a2); }
+        protected Object invoke_R2(Object a0, Object a1, Object a2) { return target(a0, a1, filter(a2)); }
+    }
+    static class F4RX extends Adapter {
+        protected F4RX(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected F4RX(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { super(e, f, t); }
+        protected F4RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
+                        { return new F4RX(e, f, t); }
+        protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3) { return target.<Object>invoke(a0, a1, a2, a3); }
+        protected Object invoke_R0(Object a0, Object a1, Object a2, Object a3) { return target(filter(a0), a1, a2, a3); }
+        protected Object invoke_R1(Object a0, Object a1, Object a2, Object a3) { return target(a0, filter(a1), a2, a3); }
+        protected Object invoke_R2(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, filter(a2), a3); }
+        protected Object invoke_R3(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, filter(a3)); }
+    }
+    // */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/FilterOneArgument.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,73 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.JavaMethodHandle;
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodType;
+
+/**
+ * Unary function composition, useful for many small plumbing jobs.
+ * The invoke method takes a single reference argument, and returns a reference
+ * Internally, it first calls the {@code filter} method on the argument,
+ * Making up the difference between the raw method type and the
+ * final method type is the responsibility of a JVM-level adapter.
+ * @author jrose
+ */
+public class FilterOneArgument extends JavaMethodHandle {
+    protected final MethodHandle filter;  // Object -> Object
+    protected final MethodHandle target;  // Object -> Object
+
+    protected Object entryPoint(Object argument) {
+        Object filteredArgument = filter.<Object>invoke(argument);
+        return target.<Object>invoke(filteredArgument);
+    }
+
+    private static final MethodHandle entryPoint =
+        MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1));
+
+    protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
+        super(entryPoint);
+        this.filter = filter;
+        this.target = target;
+    }
+
+    public static MethodHandle make(MethodHandle filter, MethodHandle target) {
+        if (filter == null)  return target;
+        if (target == null)  return filter;
+        return new FilterOneArgument(filter, target);
+    }
+
+    public String toString() {
+        return filter + "|>" + target;
+    }
+
+//    MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) {
+//        MethodHandle filter = make(filter1, filter2);
+//        return make(filter, target);
+//    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/FromGeneric.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,627 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.JavaMethodHandle;
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodType;
+import java.dyn.NoAccessException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import sun.dyn.util.ValueConversions;
+import sun.dyn.util.Wrapper;
+
+/**
+ * Adapters which mediate between incoming calls which are not generic
+ * and outgoing calls which are.  Any call can be represented generically
+ * boxing up its arguments, and (on return) unboxing the return value.
+ * <p>
+ * A call is "generic" (in MethodHandle terms) if its MethodType features
+ * only Object arguments.  A non-generic call therefore features
+ * primitives and/or reference types other than Object.
+ * An adapter has types for its incoming and outgoing calls.
+ * The incoming call type is simply determined by the adapter's type
+ * (the MethodType it presents to callers).  The outgoing call type
+ * is determined by the adapter's target (a MethodHandle that the adapter
+ * either binds internally or else takes as a leading argument).
+ * (To stretch the term, adapter-like method handles may have multiple
+ * targets or be polymorphic across multiple call types.)
+ * <p>
+ * This adapter can sometimes be more directly implemented
+ * by the JVM's built-in OP_SPREAD_ARGS adapter.
+ * @author jrose
+ */
+class FromGeneric {
+    // type for the outgoing call (may have primitives, etc.)
+    private final MethodType targetType;
+    // type of the outgoing call internal to the adapter
+    private final MethodType internalType;
+    // prototype adapter (clone and customize for each new target!)
+    private final Adapter adapter;
+    // entry point for adapter (Adapter mh, a...) => ...
+    private final MethodHandle entryPoint;
+    // unboxing invoker of type (MH, Object**N) => raw return value
+    // it makes up the difference of internalType => targetType
+    private final MethodHandle unboxingInvoker;
+    // conversion which boxes a the target's raw return value
+    private final MethodHandle returnConversion;
+
+    /** Compute and cache information common to all unboxing adapters
+     *  that can call out to targets of the erasure-family of the given erased type.
+     */
+    private FromGeneric(MethodType targetType) {
+        this.targetType = targetType;
+        MethodType internalType0;
+        // the target invoker will generally need casts on reference arguments
+        Adapter ad = findAdapter(internalType0 = targetType.erase());
+        if (ad != null) {
+            // Immediate hit to exactly the adapter we want,
+            // with no monkeying around with primitive types.
+            this.internalType = internalType0;
+            this.adapter = ad;
+            this.entryPoint = ad.prototypeEntryPoint();
+            this.returnConversion = computeReturnConversion(targetType, internalType0);
+            this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
+            return;
+        }
+
+        // outgoing primitive arguments will be wrapped; unwrap them
+        MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes();
+        MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts();
+        if (objArgsRawRet != targetType)
+            ad = findAdapter(internalType0 = objArgsRawRet);
+        if (ad == null) {
+            ad = buildAdapterFromBytecodes(internalType0 = targetType);
+        }
+        this.internalType = internalType0;
+        this.adapter = ad;
+        MethodType tepType = targetType.insertParameterType(0, adapter.getClass());
+        this.entryPoint = ad.prototypeEntryPoint();
+        this.returnConversion = computeReturnConversion(targetType, internalType0);
+        this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
+    }
+
+    /**
+     * The typed target will be called according to targetType.
+     * The adapter code will in fact see the raw result from internalType,
+     * and must box it into an object.  Produce a converter for this.
+     */
+    private static MethodHandle computeReturnConversion(
+            MethodType targetType, MethodType internalType) {
+        Class<?> tret = targetType.returnType();
+        Class<?> iret = internalType.returnType();
+        Wrapper wrap = Wrapper.forBasicType(tret);
+        if (!iret.isPrimitive()) {
+            assert(iret == Object.class);
+            return ValueConversions.identity();
+        } else if (wrap.primitiveType() == iret) {
+            return ValueConversions.box(wrap, false);
+        } else {
+            assert(tret == double.class ? iret == long.class : iret == int.class);
+            return ValueConversions.boxRaw(wrap, false);
+        }
+    }
+
+    /**
+     * The typed target will need an exact invocation point; provide it here.
+     * The adapter will possibly need to make a slightly different call,
+     * so adapt the invoker.  This way, the logic for making up the
+     * difference between what the adapter can call and what the target
+     * needs can be cached once per type.
+     */
+    private static MethodHandle computeUnboxingInvoker(
+            MethodType targetType, MethodType internalType) {
+        // All the adapters we have here have reference-untyped internal calls.
+        assert(internalType == internalType.erase());
+        MethodHandle invoker = MethodHandles.exactInvoker(targetType);
+        // cast all narrow reference types, unbox all primitive arguments:
+        MethodType fixArgsType = internalType.changeReturnType(targetType.returnType());
+        MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN,
+                                 invoker, Invokers.invokerType(fixArgsType),
+                                 invoker.type(), null);
+        if (fixArgs == null)
+            throw new InternalError("bad fixArgs");
+        // reinterpret the calling sequence as raw:
+        MethodHandle retyper = AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN,
+                                        Invokers.invokerType(internalType), fixArgs);
+        if (retyper == null)
+            throw new InternalError("bad retyper");
+        return retyper;
+    }
+
+    Adapter makeInstance(MethodHandle typedTarget) {
+        MethodType type = typedTarget.type();
+        if (type == targetType) {
+            return adapter.makeInstance(entryPoint, unboxingInvoker, returnConversion, typedTarget);
+        }
+        // my erased-type is not exactly the same as the desired type
+        assert(type.erase() == targetType);  // else we are busted
+        MethodHandle invoker = computeUnboxingInvoker(type, internalType);
+        return adapter.makeInstance(entryPoint, invoker, returnConversion, typedTarget);
+    }
+
+    /** Build an adapter of the given generic type, which invokes typedTarget
+     *  on the incoming arguments, after unboxing as necessary.
+     *  The return value is boxed if necessary.
+     * @param genericType  the required type of the result
+     * @param typedTarget the target
+     * @return an adapter method handle
+     */
+    public static MethodHandle make(MethodHandle typedTarget) {
+        MethodType type = typedTarget.type();
+        if (type == type.generic())  return typedTarget;
+        return FromGeneric.of(type).makeInstance(typedTarget);
+    }
+
+    /** Return the adapter information for this type's erasure. */
+    static FromGeneric of(MethodType type) {
+        MethodTypeImpl form = MethodTypeImpl.of(type);
+        FromGeneric fromGen = form.fromGeneric;
+        if (fromGen == null)
+            form.fromGeneric = fromGen = new FromGeneric(form.erasedType());
+        return fromGen;
+    }
+
+    public String toString() {
+        return "FromGeneric"+targetType;
+    }
+
+    /* Create an adapter that handles spreading calls for the given type. */
+    static Adapter findAdapter(MethodType internalType) {
+        MethodType entryType = internalType.generic();
+        MethodTypeImpl form = MethodTypeImpl.of(internalType);
+        Class<?> rtype = internalType.returnType();
+        int argc = form.parameterCount();
+        int lac = form.longPrimitiveParameterCount();
+        int iac = form.primitiveParameterCount() - lac;
+        String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : "");
+        String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar());
+        String cname0 = rawReturn + argc;
+        String cname1 = "A"       + argc;
+        String[] cnames = { cname0+intsAndLongs, cname0, cname1+intsAndLongs, cname1 };
+        String iname = "invoke_"+cname0+intsAndLongs;
+        // e.g., D5I2, D5, L5I2, L5; invoke_D5
+        for (String cname : cnames) {
+            Class<? extends Adapter> acls = Adapter.findSubClass(cname);
+            if (acls == null)  continue;
+            // see if it has the required invoke method
+            MethodHandle entryPoint = null;
+            try {
+                entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+            } catch (NoAccessException ex) {
+            }
+            if (entryPoint == null)  continue;
+            Constructor<? extends Adapter> ctor = null;
+            try {
+                ctor = acls.getDeclaredConstructor(MethodHandle.class);
+            } catch (NoSuchMethodException ex) {
+            } catch (SecurityException ex) {
+            }
+            if (ctor == null)  continue;
+            try {
+                // Produce an instance configured as a prototype.
+                return ctor.newInstance(entryPoint);
+            } catch (IllegalArgumentException ex) {
+            } catch (InvocationTargetException ex) {
+            } catch (InstantiationException ex) {
+            } catch (IllegalAccessException ex) {
+            }
+        }
+        return null;
+    }
+
+    static Adapter buildAdapterFromBytecodes(MethodType internalType) {
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    /**
+     * This adapter takes some untyped arguments, and returns an untyped result.
+     * Internally, it applies the invoker to the target, which causes the
+     * objects to be unboxed; the result is a raw type in L/I/J/F/D.
+     * This result is passed to convert, which is responsible for
+     * converting the raw result into a boxed object.
+     * The invoker is kept separate from the target because it can be
+     * generated once per type erasure family, and reused across adapters.
+     */
+    static abstract class Adapter extends JavaMethodHandle {
+        /*
+         * class X<<R,int N>> extends Adapter {
+         *   (MH, Object**N)=>raw(R) invoker;
+         *   (any**N)=>R target;
+         *   raw(R)=>Object convert;
+         *   Object invoke(Object**N a) = convert(invoker(target, a...))
+         * }
+         */
+        protected final MethodHandle invoker;  // (MH, Object**N) => raw(R)
+        protected final MethodHandle convert;  // raw(R) => Object
+        protected final MethodHandle target;   // (any**N) => R
+
+        protected boolean isPrototype() { return target == null; }
+        protected Adapter(MethodHandle entryPoint) {
+            this(entryPoint, null, entryPoint, null);
+            assert(isPrototype());
+        }
+        protected MethodHandle prototypeEntryPoint() {
+            if (!isPrototype())  throw new InternalError();
+            return convert;
+        }
+
+        protected Adapter(MethodHandle entryPoint,
+                          MethodHandle invoker, MethodHandle convert, MethodHandle target) {
+            super(entryPoint);
+            this.invoker = invoker;
+            this.convert = convert;
+            this.target  = target;
+        }
+
+        /** Make a copy of self, with new fields. */
+        protected abstract Adapter makeInstance(MethodHandle entryPoint,
+                MethodHandle invoker, MethodHandle convert, MethodHandle target);
+        // { return new ThisType(entryPoint, convert, target); }
+
+        /// Conversions on the value returned from the target.
+        protected Object convert_L(Object result) { return convert.<Object>invoke(result); }
+        protected Object convert_I(int    result) { return convert.<Object>invoke(result); }
+        protected Object convert_J(long   result) { return convert.<Object>invoke(result); }
+        protected Object convert_F(float  result) { return convert.<Object>invoke(result); }
+        protected Object convert_D(double result) { return convert.<Object>invoke(result); }
+
+        static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
+        static {
+            String aname = Adapter.class.getName();
+            String sname = Adapter.class.getSimpleName();
+            if (!aname.endsWith(sname))  throw new InternalError();
+            CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
+        }
+        /** Find a sibing class of Adapter. */
+        static Class<? extends Adapter> findSubClass(String name) {
+            String cname = Adapter.CLASS_PREFIX + name;
+            try {
+                return Class.forName(cname).asSubclass(Adapter.class);
+            } catch (ClassNotFoundException ex) {
+                return null;
+            } catch (ClassCastException ex) {
+                return null;
+            }
+        }
+    }
+
+    /* generated classes follow this pattern:
+    static class xA2 extends Adapter {
+        protected xA2(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected xA2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new xA2(e, i, c, t); }
+        protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
+        protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int   >invoke(target, a0, a1)); }
+        protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long  >invoke(target, a0, a1)); }
+        protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
+        protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
+    }
+    // */
+
+/*
+: SHELL; n=FromGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
+//{{{
+import java.util.*;
+class genclasses {
+    static String[] TYPES = { "Object", "int   ", "long  ", "float ", "double" };
+    static String[] TCHARS = { "L",     "I",      "J",      "F",      "D",     "A" };
+    static String[][] TEMPLATES = { {
+        "@for@ arity=0..10  rcat<=4 nrefs<=99 nints=0   nlongs=0",
+        "    //@each-cat@",
+        "    static class @cat@ extends Adapter {",
+        "        protected @cat@(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype",
+        "        protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
+        "                        { super(e, i, c, t); }",
+        "        protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
+        "                        { return new @cat@(e, i, c, t); }",
+        "        //@each-R@",
+        "        protected Object invoke_@catN@(@Tvav@) { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }",
+        "        //@end-R@",
+        "    }",
+    } };
+    static final String NEWLINE_INDENT = "\n                ";
+    enum VAR {
+        cat, catN, R, Rc, av, Tvav, Ovav;
+        public final String pattern = "@"+toString().replace('_','.')+"@";
+        public String binding;
+        static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
+            int nargs = nrefs + nints + nlongs;
+            if (topLevel)
+                VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs);
+            VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
+            VAR.R.binding = TYPES[rcat];
+            VAR.Rc.binding = TCHARS[rcat];
+            String[] Tv = new String[nargs];
+            String[] av = new String[nargs];
+            String[] Tvav = new String[nargs];
+            String[] Ovav = new String[nargs];
+            for (int i = 0; i < nargs; i++) {
+                int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2;
+                Tv[i] = TYPES[tcat];
+                av[i] = arg(i);
+                Tvav[i] = param(Tv[i], av[i]);
+                Ovav[i] = param("Object", av[i]);
+            }
+            VAR.av.binding = comma(", ", av);
+            VAR.Tvav.binding = comma(Tvav);
+            VAR.Ovav.binding = comma(Ovav);
+        }
+        static String arg(int i) { return "a"+i; }
+        static String param(String t, String a) { return t+" "+a; }
+        static String comma(String[] v) { return comma("", v); }
+        static String comma(String sep, String[] v) {
+            if (v.length == 0)  return "";
+            String res = sep+v[0];
+            for (int i = 1; i < v.length; i++)  res += ", "+v[i];
+            return res;
+        }
+        static String transform(String string) {
+            for (VAR var : values())
+                string = string.replaceAll(var.pattern, var.binding);
+            return string;
+        }
+    }
+    static String[] stringsIn(String[] strings, int beg, int end) {
+        return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
+    }
+    static String[] stringsBefore(String[] strings, int pos) {
+        return stringsIn(strings, 0, pos);
+    }
+    static String[] stringsAfter(String[] strings, int pos) {
+        return stringsIn(strings, pos, strings.length);
+    }
+    static int indexAfter(String[] strings, int pos, String tag) {
+        return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
+    }
+    static int indexBefore(String[] strings, int pos, String tag) {
+        for (int i = pos, end = strings.length; ; i++) {
+            if (i == end || strings[i].endsWith(tag))  return i;
+        }
+    }
+    static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS;
+    static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES;
+    static HashSet<String> done = new HashSet<String>();
+    public static void main(String... av) {
+        for (String[] template : TEMPLATES) {
+            int forLinesLimit = indexBefore(template, 0, "@each-cat@");
+            String[] forLines = stringsBefore(template, forLinesLimit);
+            template = stringsAfter(template, forLinesLimit);
+            for (String forLine : forLines)
+                expandTemplate(forLine, template);
+        }
+    }
+    static void expandTemplate(String forLine, String[] template) {
+        String[] params = forLine.split("[^0-9]+");
+        if (params[0].length() == 0)  params = stringsAfter(params, 1);
+        System.out.println("//params="+Arrays.asList(params));
+        int pcur = 0;
+        MIN_ARITY = Integer.valueOf(params[pcur++]);
+        MAX_ARITY = Integer.valueOf(params[pcur++]);
+        MAX_RCAT  = Integer.valueOf(params[pcur++]);
+        MAX_REFS  = Integer.valueOf(params[pcur++]);
+        MAX_INTS  = Integer.valueOf(params[pcur++]);
+        MAX_LONGS = Integer.valueOf(params[pcur++]);
+        if (pcur != params.length)  throw new RuntimeException("bad extra param: "+forLine);
+        if (MAX_RCAT >= TYPES.length)  MAX_RCAT = TYPES.length - 1;
+        ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length);
+        ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length);
+        for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) {
+            for (int rcat = 0; rcat <= MAX_RCAT; rcat++) {
+                expandTemplate(template, true, rcat, nargs, 0, 0);
+                if (ALL_ARG_TYPES)  break;
+                expandTemplateForPrims(template, true, rcat, nargs, 1, 1);
+                if (ALL_RETURN_TYPES)  break;
+            }
+        }
+    }
+    static String catstr(int rcat, int nrefs, int nints, int nlongs) {
+        int nargs = nrefs + nints + nlongs;
+        String cat = TCHARS[rcat] + nargs;
+        if (!ALL_ARG_TYPES)  cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs);
+        return cat;
+    }
+    static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) {
+        for (int isLong = 0; isLong <= 1; isLong++) {
+            for (int nprims = 1; nprims <= nargs; nprims++) {
+                int nrefs = nargs - nprims;
+                int nints = ((1-isLong) * nprims);
+                int nlongs = (isLong * nprims);
+                expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs);
+            }
+        }
+    }
+    static void expandTemplate(String[] template, boolean topLevel,
+                               int rcat, int nrefs, int nints, int nlongs) {
+        int nargs = nrefs + nints + nlongs;
+        if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS)  return;
+        VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+        if (topLevel && !done.add(VAR.cat.binding)) {
+            System.out.println("    //repeat "+VAR.cat.binding);
+            return;
+        }
+        for (int i = 0; i < template.length; i++) {
+            String line = template[i];
+            if (line.endsWith("@each-cat@")) {
+                // ignore
+            } else if (line.endsWith("@each-R@")) {
+                int blockEnd = indexAfter(template, i, "@end-R@");
+                String[] block = stringsIn(template, i+1, blockEnd-1);
+                for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++)
+                    expandTemplate(block, false, rcat1, nrefs, nints, nlongs);
+                VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+                i = blockEnd-1; continue;
+            } else if (line.endsWith("@each-Tv@")) {
+                int blockEnd = indexAfter(template, i, "@end-Tv@");
+                String[] block = stringsIn(template, i+1, blockEnd-1);
+                expandTemplate(block, false, rcat, nrefs, nints, nlongs);
+                expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1);
+                VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+                i = blockEnd-1; continue;
+            } else {
+                System.out.println(VAR.transform(line));
+            }
+        }
+    }
+}
+//}}} */
+//params=[0, 10, 4, 99, 0, 0]
+    static class A0 extends Adapter {
+        protected A0(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A0(e, i, c, t); }
+        protected Object invoke_L0() { return convert_L(invoker.<Object>invoke(target)); }
+        protected Object invoke_I0() { return convert_I(invoker.<int   >invoke(target)); }
+        protected Object invoke_J0() { return convert_J(invoker.<long  >invoke(target)); }
+        protected Object invoke_F0() { return convert_F(invoker.<float >invoke(target)); }
+        protected Object invoke_D0() { return convert_D(invoker.<double>invoke(target)); }
+    }
+    static class A1 extends Adapter {
+        protected A1(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A1(e, i, c, t); }
+        protected Object invoke_L1(Object a0) { return convert_L(invoker.<Object>invoke(target, a0)); }
+        protected Object invoke_I1(Object a0) { return convert_I(invoker.<int   >invoke(target, a0)); }
+        protected Object invoke_J1(Object a0) { return convert_J(invoker.<long  >invoke(target, a0)); }
+        protected Object invoke_F1(Object a0) { return convert_F(invoker.<float >invoke(target, a0)); }
+        protected Object invoke_D1(Object a0) { return convert_D(invoker.<double>invoke(target, a0)); }
+    }
+    static class A2 extends Adapter {
+        protected A2(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A2(e, i, c, t); }
+        protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
+        protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int   >invoke(target, a0, a1)); }
+        protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long  >invoke(target, a0, a1)); }
+        protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
+        protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
+    }
+    static class A3 extends Adapter {
+        protected A3(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A3(e, i, c, t); }
+        protected Object invoke_L3(Object a0, Object a1, Object a2) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2)); }
+        protected Object invoke_I3(Object a0, Object a1, Object a2) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2)); }
+        protected Object invoke_J3(Object a0, Object a1, Object a2) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2)); }
+        protected Object invoke_F3(Object a0, Object a1, Object a2) { return convert_F(invoker.<float >invoke(target, a0, a1, a2)); }
+        protected Object invoke_D3(Object a0, Object a1, Object a2) { return convert_D(invoker.<double>invoke(target, a0, a1, a2)); }
+    }
+    static class A4 extends Adapter {
+        protected A4(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A4(e, i, c, t); }
+        protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3)); }
+        protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3)); }
+        protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3)); }
+        protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3)); }
+        protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3)); }
+    }
+    static class A5 extends Adapter {
+        protected A5(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A5(e, i, c, t); }
+        protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4)); }
+        protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4)); }
+        protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4)); }
+        protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4)); }
+        protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4)); }
+    }
+    static class A6 extends Adapter {
+        protected A6(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A6(e, i, c, t); }
+        protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5)); }
+    }
+    static class A7 extends Adapter {
+        protected A7(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A7(e, i, c, t); }
+        protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
+    }
+    static class A8 extends Adapter {
+        protected A8(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A8(e, i, c, t); }
+        protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+    }
+    static class A9 extends Adapter {
+        protected A9(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A9(e, i, c, t); }
+        protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+    }
+    static class A10 extends Adapter {
+        protected A10(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { super(e, i, c, t); }
+        protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+                        { return new A10(e, i, c, t); }
+        protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_I(invoker.<int   >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_J(invoker.<long  >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/Invokers.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,86 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodType;
+
+
+/**
+ * Construction and caching of often-used invokers.
+ * @author jrose
+ */
+public class Invokers {
+    // exact type (sans leading taget MH) for the outgoing call
+    private final MethodType targetType;
+
+    // exact invoker for the outgoing call
+    private /*lazy*/ MethodHandle exactInvoker;
+
+    // generic (untyped) invoker for the outgoing call
+    private /*lazy*/ MethodHandle genericInvoker;
+
+    /** Compute and cache information common to all collecting adapters
+     *  that implement members of the erasure-family of the given erased type.
+     */
+    public Invokers(Access token, MethodType targetType) {
+        Access.check(token);
+        this.targetType = targetType;
+    }
+
+    public static MethodType invokerType(MethodType targetType) {
+        return targetType.insertParameterType(0, MethodHandle.class);
+    }
+
+    public MethodHandle exactInvoker() {
+        MethodHandle invoker = exactInvoker;
+        if (invoker != null)  return invoker;
+        invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType);
+        if (invoker == null)  throw new InternalError("JVM cannot find invoker for "+targetType);
+        assert(invokerType(targetType) == invoker.type());
+        exactInvoker = invoker;
+        return invoker;
+    }
+
+    public MethodHandle genericInvoker() {
+        MethodHandle invoker1 = exactInvoker();
+        MethodHandle invoker = genericInvoker;
+        if (invoker != null)  return invoker;
+        MethodType genericType = targetType.generic();
+        invoker = MethodHandles.convertArguments(invoker1, invokerType(genericType));
+        genericInvoker = invoker;
+        return invoker;
+    }
+
+    public MethodHandle varargsInvoker() {
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    public String toString() {
+        return "Invokers"+targetType;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/MemberName.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,552 @@
+/*
+ * 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 sun.dyn;
+
+import sun.dyn.util.BytecodeSignature;
+import java.dyn.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import static sun.dyn.MethodHandleNatives.Constants.*;
+
+/**
+ * Compact information which fully characterizes a method or field reference.
+ * When resolved, it includes a direct pointer to JVM metadata.
+ * This representation is stateless and only decriptive.
+ * It provides no private information and no capability to use the member.
+ * <p>
+ * By contrast, a java.lang.reflect.Method contains fuller information
+ * about the internals of a method (except its bytecodes) and also
+ * allows invocation.  A MemberName is much lighter than a reflect.Method,
+ * since it contains about 7 fields to Method's 16 (plus its sub-arrays),
+ * and those seven fields omit much of the information in Method.
+ * @author jrose
+ */
+public final class MemberName implements Member, Cloneable {
+    private Class<?>   clazz;       // class in which the method is defined
+    private String     name;        // may be null if not yet materialized
+    private Object     type;        // may be null if not yet materialized
+    private int        flags;       // modifier bits; see reflect.Modifier
+
+    private Object     vmtarget;    // VM-specific target value
+    private int        vmindex;     // method index within class or interface
+
+    { vmindex = VM_INDEX_UNINITIALIZED; }
+
+    public Class<?> getDeclaringClass() {
+        if (clazz == null && isResolved()) {
+            expandFromVM();
+        }
+        return clazz;
+    }
+
+    public ClassLoader getClassLoader() {
+        return clazz.getClassLoader();
+    }
+
+    public String getName() {
+        if (name == null) {
+            expandFromVM();
+            if (name == null)  return null;
+        }
+        return name;
+    }
+
+    public MethodType getMethodType() {
+        if (type == null) {
+            expandFromVM();
+            if (type == null)  return null;
+        }
+        if (!isInvocable())
+            throw newIllegalArgumentException("not invocable, no method type");
+        if (type instanceof MethodType) {
+            return (MethodType) type;
+        }
+        if (type instanceof String) {
+            String sig = (String) type;
+            MethodType res = MethodType.fromBytecodeString(sig, getClassLoader());
+            this.type = res;
+            return res;
+        }
+        if (type instanceof Object[]) {
+            Object[] typeInfo = (Object[]) type;
+            Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
+            Class<?> rtype = (Class<?>) typeInfo[0];
+            MethodType res = MethodType.make(rtype, ptypes);
+            this.type = res;
+            return res;
+        }
+        throw new InternalError("bad method type "+type);
+    }
+
+    public MethodType getInvocationType() {
+        MethodType itype = getMethodType();
+        if (!isStatic())
+            itype = itype.insertParameterType(0, clazz);
+        return itype;
+    }
+
+    public Class<?>[] getParameterTypes() {
+        return getMethodType().parameterArray();
+    }
+
+    public Class<?> getReturnType() {
+        return getMethodType().returnType();
+    }
+
+    public Class<?> getFieldType() {
+        if (type == null) {
+            expandFromVM();
+            if (type == null)  return null;
+        }
+        if (isInvocable())
+            throw newIllegalArgumentException("not a field or nested class, no simple type");
+        if (type instanceof Class<?>) {
+            return (Class<?>) type;
+        }
+        if (type instanceof String) {
+            String sig = (String) type;
+            MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader());
+            Class<?> res = mtype.returnType();
+            this.type = res;
+            return res;
+        }
+        throw new InternalError("bad field type "+type);
+    }
+
+    public Object getType() {
+        return (isInvocable() ? getMethodType() : getFieldType());
+    }
+
+    public String getSignature() {
+        if (type == null) {
+            expandFromVM();
+            if (type == null)  return null;
+        }
+        if (type instanceof String)
+            return (String) type;
+        if (isInvocable())
+            return BytecodeSignature.unparse(getMethodType());
+        else
+            return BytecodeSignature.unparse(getFieldType());
+    }
+
+    public int getModifiers() {
+        return (flags & RECOGNIZED_MODIFIERS);
+    }
+
+    private void setFlags(int flags) {
+        this.flags = flags;
+        assert(testAnyFlags(ALL_KINDS));
+    }
+
+    private boolean testFlags(int mask, int value) {
+        return (flags & mask) == value;
+    }
+    private boolean testAllFlags(int mask) {
+        return testFlags(mask, mask);
+    }
+    private boolean testAnyFlags(int mask) {
+        return !testFlags(mask, 0);
+    }
+
+    public boolean isStatic() {
+        return Modifier.isStatic(flags);
+    }
+    public boolean isPublic() {
+        return Modifier.isPublic(flags);
+    }
+    public boolean isPrivate() {
+        return Modifier.isPrivate(flags);
+    }
+    public boolean isProtected() {
+        return Modifier.isProtected(flags);
+    }
+    public boolean isFinal() {
+        return Modifier.isFinal(flags);
+    }
+    public boolean isAbstract() {
+        return Modifier.isAbstract(flags);
+    }
+    // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
+
+    // unofficial modifier flags, used by HotSpot:
+    static final int BRIDGE    = 0x00000040;
+    static final int VARARGS   = 0x00000080;
+    static final int SYNTHETIC = 0x00001000;
+    static final int ANNOTATION= 0x00002000;
+    static final int ENUM      = 0x00004000;
+    public boolean isBridge() {
+        return testAllFlags(IS_METHOD | BRIDGE);
+    }
+    public boolean isVarargs() {
+        return testAllFlags(VARARGS) && isInvocable();
+    }
+    public boolean isSynthetic() {
+        return testAllFlags(SYNTHETIC);
+    }
+
+    static final String CONSTRUCTOR_NAME = "<init>";  // the ever-popular
+
+    // modifiers exported by the JVM:
+    static final int RECOGNIZED_MODIFIERS = 0xFFFF;
+
+    // private flags, not part of RECOGNIZED_MODIFIERS:
+    static final int
+            IS_METHOD      = MN_IS_METHOD,      // method (not constructor)
+            IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
+            IS_FIELD       = MN_IS_FIELD,       // field
+            IS_TYPE        = MN_IS_TYPE;        // nested type
+    static final int  // for MethodHandleNatives.getMembers
+            SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
+            SEARCH_INTERFACES   = MN_SEARCH_INTERFACES;
+
+    static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
+    static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
+    static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
+    static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
+    static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
+
+    public boolean isInvocable() {
+        return testAnyFlags(IS_INVOCABLE);
+    }
+    public boolean isFieldOrMethod() {
+        return testAnyFlags(IS_FIELD_OR_METHOD);
+    }
+    public boolean isMethod() {
+        return testAllFlags(IS_METHOD);
+    }
+    public boolean isConstructor() {
+        return testAllFlags(IS_CONSTRUCTOR);
+    }
+    public boolean isField() {
+        return testAllFlags(IS_FIELD);
+    }
+    public boolean isType() {
+        return testAllFlags(IS_TYPE);
+    }
+    public boolean isPackage() {
+        return !testAnyFlags(ALL_ACCESS);
+    }
+
+    /** Initialize a query.   It is not resolved. */
+    private void init(Class<?> defClass, String name, Object type, int flags) {
+        // defining class is allowed to be null (for a naked name/type pair)
+        name.toString();  // null check
+        type.equals(type);  // null check
+        // fill in fields:
+        this.clazz = defClass;
+        this.name = name;
+        this.type = type;
+        setFlags(flags);
+        assert(!isResolved());
+    }
+
+    private void expandFromVM() {
+        if (!isResolved())  return;
+        if (type instanceof Object[])
+            type = null;  // don't saddle JVM w/ typeInfo
+        MethodHandleNatives.expand(this);
+    }
+
+    // Capturing information from the Core Reflection API:
+    private static int flagsMods(int flags, int mods) {
+        assert((flags & RECOGNIZED_MODIFIERS) == 0);
+        assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
+        return flags | mods;
+    }
+    public MemberName(Method m) {
+        Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
+        init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
+        // fill in vmtarget, vmindex while we have m in hand:
+        MethodHandleNatives.init(this, m);
+        assert(isResolved());
+    }
+    public MemberName(Constructor ctor) {
+        Object[] typeInfo = { void.class, ctor.getParameterTypes() };
+        init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
+        // fill in vmtarget, vmindex while we have ctor in hand:
+        MethodHandleNatives.init(this, ctor);
+        assert(isResolved());
+    }
+    public MemberName(Field fld) {
+        init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
+        // fill in vmtarget, vmindex while we have fld in hand:
+        MethodHandleNatives.init(this, fld);
+        assert(isResolved());
+    }
+    public MemberName(Class<?> type) {
+        init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
+        vmindex = 0;  // isResolved
+        assert(isResolved());
+    }
+
+    // bare-bones constructor; the JVM will fill it in
+    MemberName() { }
+
+    // locally useful cloner
+    @Override protected MemberName clone() {
+        try {
+            return (MemberName) super.clone();
+        } catch (CloneNotSupportedException ex) {
+            throw new InternalError();
+        }
+     }
+
+    // %%% define equals/hashcode?
+
+    // Construction from symbolic parts, for queries:
+    public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
+        init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
+    }
+    public MemberName(Class<?> defClass, String name, Class<?> type) {
+        this(defClass, name, type, 0);
+    }
+    public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
+        int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
+        init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
+    }
+    public MemberName(Class<?> defClass, String name, MethodType type) {
+        this(defClass, name, type, 0);
+    }
+
+    boolean isResolved() {
+        return (vmindex != VM_INDEX_UNINITIALIZED);
+    }
+
+    public boolean hasReceiverTypeDispatch() {
+        return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
+    }
+
+    @Override
+    public String toString() {
+        if (isType())
+            return type.toString();  // class java.lang.String
+        // else it is a field, method, or constructor
+        StringBuilder buf = new StringBuilder();
+        if (getDeclaringClass() != null) {
+            buf.append(getName(clazz));
+            buf.append('.');
+        }
+        buf.append(getName());
+        if (!isInvocable())  buf.append('/');
+        buf.append(getName(getType()));
+        /*
+        buf.append('/');
+        // key: Public, private, pRotected, sTatic, Final, sYnchronized,
+        // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
+        // (annotation), Enum, (unused)
+        final String FIELD_MOD_CHARS  = "PprTF?vt????Y?E?";
+        final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
+        String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
+        for (int i = 0; i < modChars.length(); i++) {
+            if ((flags & (1 << i)) != 0) {
+                char mc = modChars.charAt(i);
+                if (mc != '.')
+                    buf.append(mc);
+            }
+        }
+         */
+        return buf.toString();
+    }
+    private static String getName(Object obj) {
+        if (obj instanceof Class<?>)
+            return ((Class<?>)obj).getName();
+        return obj.toString();
+    }
+
+    // Queries to the JVM:
+    public int getVMIndex(Access token) {
+        Access.check(token);
+        if (!isResolved())
+            throw newIllegalStateException("not resolved");
+        return vmindex;
+    }
+//    public Object getVMTarget(Access token) {
+//        Access.check(token);
+//        if (!isResolved())
+//            throw newIllegalStateException("not resolved");
+//        return vmtarget;
+//    }
+    private RuntimeException newIllegalStateException(String message) {
+        return new IllegalStateException(message+": "+this);
+    }
+
+    // handy shared exception makers (they simplify the common case code)
+    public static RuntimeException newIllegalArgumentException(String message) {
+        return new IllegalArgumentException(message);
+    }
+    public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) {
+        return newNoAccessException("cannot access", name, lookupClass);
+    }
+    public static NoAccessException newNoAccessException(String message,
+            MemberName name, Class<?> lookupClass) {
+        message += ": " + name;
+        if (lookupClass != null)  message += ", from " + lookupClass.getName();
+        return new NoAccessException(message);
+    }
+
+    /** Actually making a query requires an access check. */
+    public static Factory getFactory(Access token) {
+        Access.check(token);
+        return Factory.INSTANCE;
+    }
+    public static Factory getFactory() {
+        return getFactory(Access.getToken());
+    }
+    public static class Factory {
+        private Factory() { } // singleton pattern
+        static Factory INSTANCE = new Factory();
+
+        private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
+
+        /// Queries
+        List<MemberName> getMembers(Class<?> defc,
+                String matchName, Object matchType,
+                int matchFlags, Class<?> lookupClass) {
+            matchFlags &= ALLOWED_FLAGS;
+            String matchSig = null;
+            if (matchType != null) {
+                matchSig = BytecodeSignature.unparse(matchType);
+                if (matchSig.startsWith("("))
+                    matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
+                else
+                    matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
+            }
+            final int BUF_MAX = 0x2000;
+            int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
+            MemberName[] buf = newMemberBuffer(len1);
+            int totalCount = 0;
+            ArrayList<MemberName[]> bufs = null;
+            for (;;) {
+                int bufCount = MethodHandleNatives.getMembers(defc,
+                        matchName, matchSig, matchFlags,
+                        MethodHandleNatives.asNativeCaller(lookupClass),
+                        totalCount, buf);
+                if (bufCount <= buf.length) {
+                    if (bufCount >= 0)
+                        totalCount += bufCount;
+                    break;
+                }
+                // JVM returned tp us with an intentional overflow!
+                totalCount += buf.length;
+                int excess = bufCount - buf.length;
+                if (bufs == null)  bufs = new ArrayList<MemberName[]>(1);
+                bufs.add(buf);
+                int len2 = buf.length;
+                len2 = Math.max(len2, excess);
+                len2 = Math.max(len2, totalCount / 4);
+                buf = newMemberBuffer(Math.min(BUF_MAX, len2));
+            }
+            ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount);
+            if (bufs != null) {
+                for (MemberName[] buf0 : bufs) {
+                    Collections.addAll(result, buf0);
+                }
+            }
+            Collections.addAll(result, buf);
+            // Signature matching is not the same as type matching, since
+            // one signature might correspond to several types.
+            // So if matchType is a Class or MethodType, refilter the results.
+            if (matchType != null && matchType != matchSig) {
+                for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
+                    MemberName m = it.next();
+                    if (!matchType.equals(m.getType()))
+                        it.remove();
+                }
+            }
+            return result;
+        }
+        boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) {
+            Class<?> caller = MethodHandleNatives.asNativeCaller(lookupClass);
+            MethodHandleNatives.resolve(m, caller);
+            if (m.isResolved())  return true;
+            int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+            String matchSig = m.getSignature();
+            MemberName[] buf = { m };
+            int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
+                    m.getName(), matchSig, matchFlags, caller, 0, buf);
+            if (n != 1)  return false;
+            return m.isResolved();
+        }
+        public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> lookupClass) {
+            MemberName result = m.clone();
+            if (resolveInPlace(result, searchSupers, lookupClass))
+                return result;
+            return null;
+        }
+        public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass) {
+            MemberName result = resolveOrNull(m, searchSupers, lookupClass);
+            if (result != null)
+                return result;
+            throw newNoAccessException(m, lookupClass);
+        }
+        public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
+                Class<?> lookupClass) {
+            return getMethods(defc, searchSupers, null, null, lookupClass);
+        }
+        public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
+                String name, MethodType type, Class<?> lookupClass) {
+            int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+            return getMembers(defc, name, type, matchFlags, lookupClass);
+        }
+        public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
+            return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
+        }
+        public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
+                Class<?> lookupClass) {
+            return getFields(defc, searchSupers, null, null, lookupClass);
+        }
+        public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
+                String name, Class<?> type, Class<?> lookupClass) {
+            int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+            return getMembers(defc, name, type, matchFlags, lookupClass);
+        }
+        public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
+                Class<?> lookupClass) {
+            int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+            return getMembers(defc, null, null, matchFlags, lookupClass);
+        }
+        private static MemberName[] newMemberBuffer(int length) {
+            MemberName[] buf = new MemberName[length];
+            // fill the buffer with dummy structs for the JVM to fill in
+            for (int i = 0; i < length; i++)
+                buf[i] = new MemberName();
+            return buf;
+        }
+    }
+
+//    static {
+//        System.out.println("Hello world!  My methods are:");
+//        System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
+//    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/MethodHandleImpl.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,355 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodHandles.Lookup;
+import java.dyn.MethodType;
+import sun.dyn.util.VerifyType;
+import java.dyn.NoAccessException;
+import static sun.dyn.MemberName.newIllegalArgumentException;
+import static sun.dyn.MemberName.newNoAccessException;
+
+/**
+ * Base class for method handles, containing JVM-specific fields and logic.
+ * TO DO:  It should not be a base class.
+ * @author jrose
+ */
+public abstract class MethodHandleImpl {
+
+    // Fields which really belong in MethodHandle:
+    private byte       vmentry;    // adapter stub or method entry point
+    //private int      vmslots;    // optionally, hoist type.form.vmslots
+    protected Object   vmtarget;   // VM-specific, class-specific target value
+    //MethodType       type;       // defined in MethodHandle
+
+    // TO DO:  vmtarget should be invisible to Java, since the JVM puts internal
+    // managed pointers into it.  Making it visible exposes it to debuggers,
+    // which can cause errors when they treat the pointer as an Object.
+
+    // These two dummy fields are present to force 'I' and 'J' signatures
+    // into this class's constant pool, so they can be transferred
+    // to vmentry when this class is loaded.
+    static final int  INT_FIELD = 0;
+    static final long LONG_FIELD = 0;
+
+    // type is defined in java.dyn.MethodHandle, which is platform-independent
+
+    // vmentry (a void* field) is used *only* by by the JVM.
+    // The JVM adjusts its type to int or long depending on system wordsize.
+    // Since it is statically typed as neither int nor long, it is impossible
+    // to use this field from Java bytecode.  (Please don't try to, either.)
+
+    // The vmentry is an assembly-language stub which is jumped to
+    // immediately after the method type is verified.
+    // For a direct MH, this stub loads the vmtarget's entry point
+    // and jumps to it.
+
+    /**
+     * VM-based method handles must have a security token.
+     * This security token can only be obtained by trusted code.
+     * Do not create method handles directly; use factory methods.
+     */
+    public MethodHandleImpl(Access token) {
+        Access.check(token);
+    }
+
+    /** Initialize the method type form to participate in JVM calls.
+     *  This is done once for each erased type.
+     */
+    public static void init(Access token, MethodType self) {
+        Access.check(token);
+        if (MethodHandleNatives.JVM_SUPPORT)
+            MethodHandleNatives.init(self);
+    }
+
+    /// Factory methods to create method handles:
+
+    private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
+
+    static private Lookup IMPL_LOOKUP_INIT;
+
+    public static void initLookup(Access token, Lookup lookup) {
+        Access.check(token);
+        if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != Access.class)
+            throw new InternalError();
+        IMPL_LOOKUP_INIT = lookup;
+    }
+
+    public static Lookup getLookup(Access token) {
+        Access.check(token);
+        return IMPL_LOOKUP;
+    }
+
+    static {
+        // Force initialization:
+        Lookup.PUBLIC_LOOKUP.lookupClass();
+        if (IMPL_LOOKUP_INIT == null)
+            throw new InternalError();
+    }
+
+    public static void initStatics() {
+        // Trigger preceding sequence.
+    }
+
+    /** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */
+    static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT;
+
+
+    /** Look up a given method.
+     * Callable only from java.dyn and related packages.
+     * <p>
+     * The resulting method handle type will be of the given type,
+     * with a receiver type {@code rcvc} prepended if the member is not static.
+     * <p>
+     * Access checks are made as of the given lookup class.
+     * In particular, if the method is protected and {@code defc} is in a
+     * different package from the lookup class, then {@code rcvc} must be
+     * the lookup class or a subclass.
+     * @param token Proof that the lookup class has access to this package.
+     * @param member Resolved method or constructor to call.
+     * @param name Name of the desired method.
+     * @param rcvc Receiver type of desired non-static method (else null)
+     * @param doDispatch whether the method handle will test the receiver type
+     * @param lookupClass access-check relative to this class
+     * @return a direct handle to the matching method
+     * @throws NoAccessException if the given method cannot be accessed by the lookup class
+     */
+    public static
+    MethodHandle findMethod(Access token, MemberName method,
+            boolean doDispatch, Class<?> lookupClass) {
+        Access.check(token);  // only trusted calls
+        MethodType mtype = method.getMethodType();
+        if (method.isStatic()) {
+            doDispatch = false;
+        } else {
+            // adjust the advertised receiver type to be exactly the one requested
+            // (in the case of invokespecial, this will be the calling class)
+            mtype = mtype.insertParameterType(0, method.getDeclaringClass());
+            if (method.isConstructor())
+                doDispatch = true;
+        }
+        DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
+        if (!mh.isValid())
+            throw newNoAccessException(method, lookupClass);
+        return mh;
+    }
+
+    public static
+    MethodHandle accessField(Access token,
+                           MemberName member, boolean isSetter,
+                           Class<?> lookupClass) {
+        Access.check(token);
+        // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    public static
+    MethodHandle accessArrayElement(Access token,
+                           Class<?> arrayClass, boolean isSetter) {
+        Access.check(token);
+        if (!arrayClass.isArray())
+            throw newIllegalArgumentException("not an array: "+arrayClass);
+        // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Bind a predetermined first argument to the given direct method handle.
+     * Callable only from MethodHandles.
+     * @param token Proof that the caller has access to this package.
+     * @param target Any direct method handle.
+     * @param receiver Receiver (or first static method argument) to pre-bind.
+     * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
+     */
+    public static
+    MethodHandle bindReceiver(Access token,
+                              MethodHandle target, Object receiver) {
+        Access.check(token);
+        if (target instanceof DirectMethodHandle)
+            return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
+        return null;   // let caller try something else
+    }
+
+    /** Bind a predetermined argument to the given arbitrary method handle.
+     * Callable only from MethodHandles.
+     * @param token Proof that the caller has access to this package.
+     * @param target Any method handle.
+     * @param receiver Argument (which can be a boxed primitive) to pre-bind.
+     * @return a suitable BoundMethodHandle
+     */
+    public static
+    MethodHandle bindArgument(Access token,
+                              MethodHandle target, int argnum, Object receiver) {
+        Access.check(token);
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    public static MethodHandle convertArguments(Access token,
+                                                MethodHandle target,
+                                                MethodType newType,
+                                                MethodType oldType,
+                                                int[] permutationOrNull) {
+        Access.check(token);
+        MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
+        if (res != null)
+            return res;
+        int argc = oldType.parameterCount();
+        // The JVM can't do it directly, so fill in the gap with a Java adapter.
+        // TO DO: figure out what to put here from case-by-case experience
+        // Use a heavier method:  Convert all the arguments to Object,
+        // then back to the desired types.  We might have to use Java-based
+        // method handles to do this.
+        MethodType objType = MethodType.makeGeneric(argc);
+        MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target);
+        if (objTarget == null)
+            objTarget = FromGeneric.make(target);
+        res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget);
+        if (res != null)
+            return res;
+        return ToGeneric.make(newType, objTarget);
+    }
+
+    public static MethodHandle spreadArguments(Access token,
+                                               MethodHandle target,
+                                               MethodType newType,
+                                               int spreadArg) {
+        Access.check(token);
+        // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
+        MethodType oldType = target.type();
+        // spread the last argument of newType to oldType
+        int spreadCount = oldType.parameterCount() - spreadArg;
+        Class<Object[]> spreadArgType = Object[].class;
+        MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
+        if (res != null)
+            return res;
+        // try an intermediate adapter
+        Class<?> spreadType = null;
+        if (spreadArg < 0 || spreadArg >= newType.parameterCount()
+            || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
+            throw newIllegalArgumentException("no restarg in "+newType);
+        Class<?>[] ptypes = oldType.parameterArray();
+        for (int i = 0; i < spreadCount; i++)
+            ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
+        MethodType midType = MethodType.make(newType.returnType(), ptypes);
+        // after spreading, some arguments may need further conversion
+        target = convertArguments(token, target, midType, oldType, null);
+        if (target == null)
+            throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
+        res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
+        return res;
+    }
+
+    public static MethodHandle collectArguments(Access token,
+                                                MethodHandle target,
+                                                MethodType newType,
+                                                int collectArg) {
+        if (collectArg > 0)
+            throw new UnsupportedOperationException("NYI");
+        throw new UnsupportedOperationException("NYI");
+    }
+    public static
+    MethodHandle dropArguments(Access token, MethodHandle target,
+                               MethodType newType, int argnum) {
+        Access.check(token);
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    public static
+    MethodHandle makeGuardWithTest(Access token,
+                                   final MethodHandle test,
+                                   final MethodHandle target,
+                                   final MethodHandle fallback) {
+        Access.check(token);
+        // %%% This is just a sketch.  It needs to be de-boxed.
+        // Adjust the handles to accept varargs lists.
+        MethodType type = target.type();
+        Class<?>  rtype = type.returnType();
+        if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) {
+            MethodType vatestType   = MethodType.make(boolean.class, Object[].class);
+            MethodType vatargetType = MethodType.make(rtype, Object[].class);
+            MethodHandle vaguard = makeGuardWithTest(token,
+                    MethodHandles.spreadArguments(test, vatestType),
+                    MethodHandles.spreadArguments(target, vatargetType),
+                    MethodHandles.spreadArguments(fallback, vatargetType));
+            return MethodHandles.collectArguments(vaguard, type);
+        }
+        if (rtype.isPrimitive()) {
+            MethodType boxtype = type.changeReturnType(Object.class);
+            MethodHandle boxguard = makeGuardWithTest(token,
+                    test,
+                    MethodHandles.convertArguments(target, boxtype),
+                    MethodHandles.convertArguments(fallback, boxtype));
+            return MethodHandles.convertArguments(boxguard, type);
+        }
+        // Got here?  Reduced calling sequence to Object(Object).
+        class Guarder {
+            Object invoke(Object x) {
+                // If javac supports MethodHandle.invoke directly:
+                //z = vatest.invoke<boolean>(arguments);
+                // If javac does not support direct MH.invoke calls:
+                boolean z = (Boolean) MethodHandles.invoke_1(test, x);
+                MethodHandle mh = (z ? target : fallback);
+                return MethodHandles.invoke_1(mh, x);
+            }
+            MethodHandle handle() {
+                MethodType invokeType = MethodType.makeGeneric(0, true);
+                MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType);
+                return MethodHandles.collectArguments(vh, target.type());
+            }
+        }
+        return new Guarder().handle();
+    }
+
+    public static
+    MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
+        Access.check(token);
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    protected static String basicToString(MethodHandle target) {
+        MemberName name = null;
+        if (target != null)
+            name = MethodHandleNatives.getMethodName(target);
+        if (name == null)
+            return "<unknown>";
+        return name.getName();
+    }
+
+    protected static String addTypeString(MethodHandle target, String name) {
+        if (target == null)  return name;
+        return name+target.type();
+    }
+    static RuntimeException newIllegalArgumentException(String string) {
+        return new IllegalArgumentException(string);
+    }
+
+    @Override
+    public String toString() {
+        MethodHandle self = (MethodHandle) this;
+        return addTypeString(self, basicToString(self));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/MethodHandleNatives.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,271 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.MethodHandle;
+import java.dyn.MethodType;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import static sun.dyn.MethodHandleNatives.Constants.*;
+
+/**
+ * The JVM interface for the method handles package is all here.
+ * @author jrose
+ */
+class MethodHandleNatives {
+
+    private MethodHandleNatives() { } // static only
+
+    /// MethodName support
+
+    static native void init(MemberName self, Object ref);
+    static native void expand(MemberName self);
+    static native void resolve(MemberName self, Class<?> caller);
+    static native int getMembers(Class<?> defc, String matchName, String matchSig,
+            int matchFlags, Class<?> caller, int skip, MemberName[] results);
+
+    static Class<?> asNativeCaller(Class<?> lookupClass) {
+        if (lookupClass == null)  // means "public only, non-privileged"
+            return sun.dyn.empty.Empty.class;
+        if (lookupClass == Access.class)  // means "internal, privileged"
+            return null;    // to the JVM, null means completely privileged
+        return lookupClass;
+    }
+
+    /// MethodHandle support
+
+    /** Initialize the method handle to adapt the call. */
+    static native void init(AdapterMethodHandle self, MethodHandle target, int argnum);
+    /** Initialize the method handle to call the correct method, directly. */
+    static native void init(BoundMethodHandle self, Object target, int argnum);
+    /** Initialize the method handle to call as if by an invoke* instruction. */
+    static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class<?> caller);
+
+    /** Initialize a method type, once per form. */
+    static native void init(MethodType self);
+
+    /** Tell the JVM that we need to change the target of an invokedynamic. */
+    static native void linkCallSite(CallSiteImpl site, MethodHandle target);
+
+    /** Fetch the vmtarget field.
+     *  It will be sanitized as necessary to avoid exposing non-Java references.
+     *  This routine is for debugging and reflection.
+     */
+    static native Object getTarget(MethodHandle self, int format);
+
+    /** Fetch the name of the handled method, if available.
+     *  This routine is for debugging and reflection.
+     */
+    static MemberName getMethodName(MethodHandle self) {
+        if (!JVM_SUPPORT)  return null;
+        return (MemberName) getTarget(self, ETF_METHOD_NAME);
+    }
+
+    /** Fetch the reflective version of the handled method, if available.
+     */
+    static AccessibleObject getTargetMethod(MethodHandle self) {
+        if (!JVM_SUPPORT)  return null;
+        return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
+    }
+
+    /** Fetch the target of this method handle.
+     *  If it directly targets a method, return a tuple of method info.
+     *  The info is of the form new Object[]{defclass, name, sig, refclass}.
+     *  If it is chained to another method handle, return that handle.
+     */
+    static Object getTargetInfo(MethodHandle self) {
+        if (!JVM_SUPPORT)  return null;
+        return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
+    }
+
+    static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) {
+        return new Object[] { defc, name, sig, mods, refc };
+    }
+
+    /** Fetch MH-related JVM parameter.
+     *  which=0 retrieves MethodHandlePushLimit
+     *  which=1 retrieves stack slot push size (in address units)
+     */
+    static native int getConstant(int which);
+
+    /** True iff this HotSpot JVM has built-in support for method handles.
+     * If false, some test cases might run, but functionality will be missing.
+     */
+    public static final boolean JVM_SUPPORT;
+
+    /** Java copy of MethodHandlePushLimit in range 2..255. */
+    static final int JVM_PUSH_LIMIT;
+    /** JVM stack motion (in words) after one slot is pushed, usually -1.
+     */
+    static final int JVM_STACK_MOVE_UNIT;
+
+    private static native void registerNatives();
+    static {
+        boolean JVM_SUPPORT_;
+        int     JVM_PUSH_LIMIT_;
+        int     JVM_STACK_MOVE_UNIT_;
+        try {
+            registerNatives();
+            JVM_SUPPORT_ = true;
+            JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
+            JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT);
+            //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
+        } catch (UnsatisfiedLinkError ee) {
+            // ignore; if we use init() methods later we'll see linkage errors
+            JVM_SUPPORT_ = false;
+            JVM_PUSH_LIMIT_ = 3;  // arbitrary
+            JVM_STACK_MOVE_UNIT_ = -1;  // arbitrary
+            //System.out.println("Warning: Running with JVM_SUPPORT=false");
+            //System.out.println(ee);
+            JVM_SUPPORT = JVM_SUPPORT_;
+            JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
+            JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
+            throw ee;  // just die; hopeless to try to run with an older JVM
+        }
+        JVM_SUPPORT = JVM_SUPPORT_;
+        JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
+        JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
+    }
+
+    // All compile-time constants go here.
+    // There is an opportunity to check them against the JVM's idea of them.
+    static class Constants {
+        Constants() { } // static only
+        // MethodHandleImpl
+        static final int // for getConstant
+                GC_JVM_PUSH_LIMIT = 0,
+                GC_JVM_STACK_MOVE_LIMIT = 1;
+        static final int
+                ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
+                ETF_DIRECT_HANDLE         = 1, // ultimate method handle (will be a DMH, may be self)
+                ETF_METHOD_NAME           = 2, // ultimate method as MemberName
+                ETF_REFLECT_METHOD        = 3; // ultimate method as java.lang.reflect object (sans refClass)
+
+        // MemberName
+        // The JVM uses values of -2 and above for vtable indexes.
+        // Field values are simple positive offsets.
+        // Ref: src/share/vm/oops/methodOop.hpp
+        // This value is negative enough to avoid such numbers,
+        // but not too negative.
+        static final int
+                MN_IS_METHOD           = 0x00010000, // method (not constructor)
+                MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
+                MN_IS_FIELD            = 0x00040000, // field
+                MN_IS_TYPE             = 0x00080000, // nested type
+                MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
+                MN_SEARCH_INTERFACES   = 0x00200000, // for MHN.getMembers
+                VM_INDEX_UNINITIALIZED = -99;
+
+        // AdapterMethodHandle
+        /** Conversions recognized by the JVM.
+         *  They must align with the constants in sun.dyn_AdapterMethodHandle,
+         *  in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp.
+         */
+        static final int
+            OP_RETYPE_ONLY   = 0x0, // no argument changes; straight retype
+            OP_CHECK_CAST    = 0x1, // ref-to-ref conversion; requires a Class argument
+            OP_PRIM_TO_PRIM  = 0x2, // converts from one primitive to another
+            OP_REF_TO_PRIM   = 0x3, // unboxes a wrapper to produce a primitive
+            OP_PRIM_TO_REF   = 0x4, // boxes a primitive into a wrapper (NYI)
+            OP_SWAP_ARGS     = 0x5, // swap arguments (vminfo is 2nd arg)
+            OP_ROT_ARGS      = 0x6, // rotate arguments (vminfo is displaced arg)
+            OP_DUP_ARGS      = 0x7, // duplicates one or more arguments (at TOS)
+            OP_DROP_ARGS     = 0x8, // remove one or more argument slots
+            OP_COLLECT_ARGS  = 0x9, // combine one or more arguments into a varargs (NYI)
+            OP_SPREAD_ARGS   = 0xA, // expand in place a varargs array (of known size)
+            OP_FLYBY         = 0xB, // operate first on reified argument list (NYI)
+            OP_RICOCHET      = 0xC, // run an adapter chain on the return value (NYI)
+            CONV_OP_LIMIT    = 0xD; // limit of CONV_OP enumeration
+        /** Shift and mask values for decoding the AMH.conversion field.
+         *  These numbers are shared with the JVM for creating AMHs.
+         */
+        static final int
+            CONV_OP_MASK     = 0xF00, // this nybble contains the conversion op field
+            CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
+            CONV_VMINFO_SHIFT     =  0, // position of bits in CONV_VMINFO_MASK
+            CONV_OP_SHIFT         =  8, // position of bits in CONV_OP_MASK
+            CONV_DEST_TYPE_SHIFT  = 12, // byte 2 has the adapter BasicType (if needed)
+            CONV_SRC_TYPE_SHIFT   = 16, // byte 2 has the source BasicType (if needed)
+            CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
+            CONV_STACK_MOVE_MASK  = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
+
+        /** Which conv-ops are implemented by the JVM? */
+        static final int CONV_OP_IMPLEMENTED_MASK =
+                // TODO: The following expression should be replaced by
+                // a JVM query.
+                ((1<<OP_RETYPE_ONLY)
+                |(1<<OP_CHECK_CAST)
+                |(1<<OP_PRIM_TO_PRIM)
+                |(1<<OP_REF_TO_PRIM)
+                |(1<<OP_SWAP_ARGS)
+                |(1<<OP_ROT_ARGS)
+                |(1<<OP_DUP_ARGS)
+                |(1<<OP_DROP_ARGS)
+                );
+
+        /**
+         * Basic types as encoded in the JVM.  These code values are not
+         * intended for use outside this class.  They are used as part of
+         * a private interface between the JVM and this class.
+         */
+        static final int
+            T_BOOLEAN  =  4,
+            T_CHAR     =  5,
+            T_FLOAT    =  6,
+            T_DOUBLE   =  7,
+            T_BYTE     =  8,
+            T_SHORT    =  9,
+            T_INT      = 10,
+            T_LONG     = 11,
+            T_OBJECT   = 12,
+            //T_ARRAY    = 13
+            T_VOID     = 14;
+            //T_ADDRESS  = 15
+    }
+
+    private static native int getNamedCon(int which, Object[] name);
+    static boolean verifyConstants() {
+        Object[] box = { null };
+        for (int i = 0; ; i++) {
+            box[0] = null;
+            int vmval = getNamedCon(i, box);
+            if (box[0] == null)  break;
+            String name = (String) box[0];
+            try {
+                Field con = Constants.class.getDeclaredField(name);
+                int jval = con.getInt(null);
+                if (jval != vmval)
+                    throw new InternalError(name+": JVM has "+vmval+" while Java has "+jval);
+            } catch (Exception ex) {
+                throw new InternalError(name+": access failed, got "+ex);
+            }
+        }
+        return true;
+    }
+    static {
+        if (JVM_SUPPORT)  verifyConstants();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/MethodTypeImpl.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,502 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.*;
+import sun.dyn.util.Wrapper;
+
+/**
+ * Shared information for a group of method types, which differ
+ * only by reference types, and therefore share a common erasure
+ * and wrapping.
+ * <p>
+ * For an empirical discussion of the structure of method types,
+ * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
+ * the thread "Avoiding Boxing" on jvm-languages</a>.
+ * There are approximately 2000 distinct erased method types in the JDK.
+ * There are a little over 10 times that number of unerased types.
+ * No more than half of these are likely to be loaded at once.
+ * @author John Rose
+ */
+public class MethodTypeImpl {
+    final int[] argToSlotTable, slotToArgTable;
+    final long argCounts;               // packed slot & value counts
+    final long primCounts;              // packed prim & double counts
+    final int vmslots;                  // total number of parameter slots
+    final MethodType erasedType;        // the canonical erasure
+    /*lazy*/ MethodType primsAsBoxes;   // replace prims by wrappers
+    /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
+    /*lazy*/ MethodType primsAsInts;    // replace prims by int/long
+    /*lazy*/ MethodType primsAsLongs;   // replace prims by long
+    /*lazy*/ MethodType primsAtEnd;     // reorder primitives to the end
+
+    // Cached adapter information:
+    /*lazy*/ ToGeneric   toGeneric;     // convert cs. with prims to w/o
+    /*lazy*/ FromGeneric fromGeneric;   // convert cs. w/o prims to with
+    /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
+    ///*lazy*/ Invokers    invokers;    // cache of handy higher-order adapters
+
+    public MethodType erasedType() {
+        return erasedType;
+    }
+
+    public static MethodTypeImpl of(MethodType type) {
+        return METHOD_TYPE_FRIEND.form(type);
+    }
+
+    /** Access methods for the internals of MethodType, supplied to
+     *  MethodTypeForm as a trusted agent.
+     */
+    static public interface MethodTypeFriend {
+        Class<?>[]     ptypes(MethodType mt);
+        MethodTypeImpl form(MethodType mt);
+        void           setForm(MethodType mt, MethodTypeImpl form);
+        MethodType     makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
+        MethodTypeImpl newMethodTypeForm(MethodType mt);
+        Invokers       getInvokers(MethodType mt);
+        void           setInvokers(MethodType mt, Invokers inv);
+    }
+    public static void setMethodTypeFriend(Access token, MethodTypeFriend am) {
+        Access.check(token);
+        if (METHOD_TYPE_FRIEND != null)
+            throw new InternalError();  // just once
+        METHOD_TYPE_FRIEND = am;
+    }
+    static private MethodTypeFriend METHOD_TYPE_FRIEND;
+
+    protected MethodTypeImpl(MethodType erasedType) {
+        this.erasedType = erasedType;
+
+        Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType);
+        int ptypeCount = ptypes.length;
+        int pslotCount = ptypeCount;            // temp. estimate
+        int rtypeCount = 1;                     // temp. estimate
+        int rslotCount = 1;                     // temp. estimate
+
+        int[] argToSlotTab = null, slotToArgTab = null;
+
+        // Walk the argument types, looking for primitives.
+        int pac = 0, lac = 0, prc = 0, lrc = 0;
+        Class<?> epts[] = ptypes;
+        for (int i = 0; i < epts.length; i++) {
+            Class<?> pt = epts[i];
+            if (pt != Object.class) {
+                assert(pt.isPrimitive());
+                ++pac;
+                if (hasTwoArgSlots(pt))  ++lac;
+            }
+        }
+        pslotCount += lac;                  // #slots = #args + #longs
+        Class<?> rt = erasedType.returnType();
+        if (rt != Object.class) {
+            ++prc;          // even void.class counts as a prim here
+            if (hasTwoArgSlots(rt))  ++lrc;
+            // adjust #slots, #args
+            if (rt == void.class)
+                rtypeCount = rslotCount = 0;
+            else
+                rslotCount += lrc;
+        }
+        if (lac != 0) {
+            int slot = ptypeCount + lac;
+            slotToArgTab = new int[slot+1];
+            argToSlotTab = new int[1+ptypeCount];
+            argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+            for (int i = 0; i < epts.length; i++) {
+                Class<?> pt = epts[i];
+                if (hasTwoArgSlots(pt))  --slot;
+                --slot;
+                slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                argToSlotTab[1+i]  = slot;
+            }
+            assert(slot == 0);  // filled the table
+        }
+        this.primCounts = pack(lrc, prc, lac, pac);
+        this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
+        if (slotToArgTab == null) {
+            int slot = ptypeCount; // first arg is deepest in stack
+            slotToArgTab = new int[slot+1];
+            argToSlotTab = new int[1+ptypeCount];
+            argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+            for (int i = 0; i < ptypeCount; i++) {
+                --slot;
+                slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                argToSlotTab[1+i]  = slot;
+            }
+        }
+        this.argToSlotTable = argToSlotTab;
+        this.slotToArgTable = slotToArgTab;
+
+        if (pslotCount >= 256)  throw new IllegalArgumentException("too many arguments");
+
+        // send a few bits down to the JVM:
+        this.vmslots = parameterSlotCount();
+
+        // short circuit some no-op canonicalizations:
+        if (!hasPrimitives()) {
+            primsAsBoxes = erasedType;
+            primArgsAsBoxes = erasedType;
+            primsAsInts  = erasedType;
+            primsAsLongs = erasedType;
+            primsAtEnd   = erasedType;
+        }
+    }
+
+    /** Turn all primitive types to corresponding wrapper types.
+     */
+    public MethodType primsAsBoxes() {
+        MethodType ct = primsAsBoxes;
+        if (ct != null)  return ct;
+        MethodType t = erasedType;
+        ct = canonicalize(erasedType, WRAP, WRAP);
+        if (ct == null)  ct = t;  // no prims to box
+        return primsAsBoxes = ct;
+    }
+
+    /** Turn all primitive argument types to corresponding wrapper types.
+     *  Subword and void return types are promoted to int.
+     */
+    public MethodType primArgsAsBoxes() {
+        MethodType ct = primArgsAsBoxes;
+        if (ct != null)  return ct;
+        MethodType t = erasedType;
+        ct = canonicalize(erasedType, RAW_RETURN, WRAP);
+        if (ct == null)  ct = t;  // no prims to box
+        return primArgsAsBoxes = ct;
+    }
+
+    /** Turn all primitive types to either int or long.
+     *  Floating point return types are not changed, because
+     *  they may require special calling sequences.
+     *  A void return value is turned to int.
+     */
+    public MethodType primsAsInts() {
+        MethodType ct = primsAsInts;
+        if (ct != null)  return ct;
+        MethodType t = erasedType;
+        ct = canonicalize(t, RAW_RETURN, INTS);
+        if (ct == null)  ct = t;  // no prims to int-ify
+        return primsAsInts = ct;
+    }
+
+    /** Turn all primitive types to either int or long.
+     *  Floating point return types are not changed, because
+     *  they may require special calling sequences.
+     *  A void return value is turned to int.
+     */
+    public MethodType primsAsLongs() {
+        MethodType ct = primsAsLongs;
+        if (ct != null)  return ct;
+        MethodType t = erasedType;
+        ct = canonicalize(t, RAW_RETURN, LONGS);
+        if (ct == null)  ct = t;  // no prims to int-ify
+        return primsAsLongs = ct;
+    }
+
+    /** Stably sort parameters into 3 buckets: ref, int, long. */
+    public MethodType primsAtEnd() {
+        MethodType ct = primsAtEnd;
+        if (ct != null)  return ct;
+        MethodType t = erasedType;
+
+        int pac = primitiveParameterCount();
+        if (pac == 0)
+            return primsAtEnd = t;
+
+        int argc = parameterCount();
+        int lac = longPrimitiveParameterCount();
+        if (pac == argc && (lac == 0 || lac == argc))
+            return primsAtEnd = t;
+
+        // known to have a mix of 2 or 3 of ref, int, long
+        return primsAtEnd = reorderParameters(t, primsAtEndOrder(t), null);
+
+    }
+
+    /** Compute a new ordering of parameters so that all references
+     *  are before all ints or longs, and all ints are before all longs.
+     *  For this ordering, doubles count as longs, and all other primitive
+     *  values count as ints.
+     *  As a special case, if the parameters are already in the specified
+     *  order, this method returns a null reference, rather than an array
+     *  specifying a null permutation.
+     *  <p>
+     *  For example, the type {@code (int,boolean,int,Object,String)void}
+     *  produces the order {@code {3,4,0,1,2}}, the type
+     *  {@code (long,int,String)void} produces {@code {2,1,2}}, and
+     *  the type {@code (Object,int)Object} produces {@code null}.
+     */
+    public static int[] primsAtEndOrder(MethodType mt) {
+        MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt);
+        if (form.primsAtEnd == form.erasedType)
+            // quick check shows no reordering is necessary
+            return null;
+
+        int argc = form.parameterCount();
+        int[] paramOrder = new int[argc];
+
+        // 3-way bucket sort:
+        int pac = form.primitiveParameterCount();
+        int lac = form.longPrimitiveParameterCount();
+        int rfill = 0, ifill = argc - pac, lfill = argc - lac;
+
+        Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
+        boolean changed = false;
+        for (int i = 0; i < ptypes.length; i++) {
+            Class<?> pt = ptypes[i];
+            int ord;
+            if (!pt.isPrimitive())             ord = rfill++;
+            else if (!hasTwoArgSlots(pt))      ord = ifill++;
+            else                               ord = lfill++;
+            if (ord != i)  changed = true;
+            paramOrder[i] = ord;
+        }
+        assert(rfill == argc - pac && ifill == argc - lac && lfill == argc);
+        if (!changed) {
+            form.primsAtEnd = form.erasedType;
+            return null;
+        }
+        return paramOrder;
+    }
+
+    /** Put the existing parameters of mt into a new order, given by newParamOrder.
+     *  The third argument is logically appended to mt.parameterArray,
+     *  so that elements of newParamOrder can index either pre-existing or
+     *  new parameter types.
+     */
+    public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class<?>[] moreParams) {
+        if (newParamOrder == null)  return mt;  // no-op reordering
+        Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
+        Class<?>[] ntypes = new Class<?>[newParamOrder.length];
+        int ordMax = ptypes.length + (moreParams == null ? 0 : moreParams.length);
+        boolean changed = (ntypes.length != ptypes.length);
+        for (int i = 0; i < newParamOrder.length; i++) {
+            int ord = newParamOrder[i];
+            if (ord != i)  changed = true;
+            Class<?> nt;
+            if (ord < ptypes.length)   nt = ptypes[ord];
+            else if (ord == ordMax)    nt = mt.returnType();
+            else                       nt = moreParams[ord - ptypes.length];
+            ntypes[i] = nt;
+        }
+        if (!changed)  return mt;
+        return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true);
+    }
+
+    private static boolean hasTwoArgSlots(Class<?> type) {
+        return type == long.class || type == double.class;
+    }
+
+    private static long pack(int a, int b, int c, int d) {
+        assert(((a|b|c|d) & ~0xFFFF) == 0);
+        long hw = ((a << 16) | b), lw = ((c << 16) | d);
+        return (hw << 32) | lw;
+    }
+    private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
+        assert(word <= 3);
+        return (char)(packed >> ((3-word) * 16));
+    }
+
+    public int parameterCount() {                      // # outgoing values
+        return unpack(argCounts, 3);
+    }
+    public int parameterSlotCount() {                  // # outgoing interpreter slots
+        return unpack(argCounts, 2);
+    }
+    public int returnCount() {                         // = 0 (V), or 1
+        return unpack(argCounts, 1);
+    }
+    public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
+        return unpack(argCounts, 0);
+    }
+    public int primitiveParameterCount() {
+        return unpack(primCounts, 3);
+    }
+    public int longPrimitiveParameterCount() {
+        return unpack(primCounts, 2);
+    }
+    public int primitiveReturnCount() {                // = 0 (obj), or 1
+        return unpack(primCounts, 1);
+    }
+    public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
+        return unpack(primCounts, 0);
+    }
+    public boolean hasPrimitives() {
+        return primCounts != 0;
+    }
+//    public boolean hasNonVoidPrimitives() {
+//        if (primCounts == 0)  return false;
+//        if (primitiveParameterCount() != 0)  return true;
+//        return (primitiveReturnCount() != 0 && returnCount() != 0);
+//    }
+    public boolean hasLongPrimitives() {
+        return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
+    }
+    public int parameterToArgSlot(int i) {
+        return argToSlotTable[1+i];
+    }
+    public int argSlotToParameter(int argSlot) {
+        // Note:  Empty slots are represented by zero in this table.
+        // Valid arguments slots contain incremented entries, so as to be non-zero.
+        // We return -1 the caller to mean an empty slot.
+        return slotToArgTable[argSlot] - 1;
+    }
+
+    public static void initForm(Access token, MethodType mt) {
+        Access.check(token);
+        MethodTypeImpl form = findForm(mt);
+        METHOD_TYPE_FRIEND.setForm(mt, form);
+        if (form.erasedType == mt) {
+            // This is a principal (erased) type; show it to the JVM.
+            MethodHandleImpl.init(token, mt);
+        }
+    }
+
+    static MethodTypeImpl findForm(MethodType mt) {
+        MethodType erased = canonicalize(mt, ERASE, ERASE);
+        if (erased == null) {
+            // It is already erased.  Make a new MethodTypeForm.
+            return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
+        } else {
+            // Share the MethodTypeForm with the erased version.
+            return METHOD_TYPE_FRIEND.form(erased);
+        }
+    }
+
+    /** Codes for {@link #canonicalize(java.lang.Class, int).
+     * ERASE means change every reference to {@code Object}.
+     * WRAP means convert primitives (including {@code void} to their
+     * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
+     * INTS means convert all non-void primitive types to int or long,
+     * according to size.  LONGS means convert all non-void primitives
+     * to long, regardless of size.  RAW_RETURN means convert a type
+     * (assumed to be a return type) to int if it is smaller than an int,
+     * or if it is void.
+     */
+    public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
+
+    /** Canonicalize the types in the given method type.
+     * If any types change, intern the new type, and return it.
+     * Otherwise return null.
+     */
+    public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
+        Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
+        Class<?>[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs);
+        Class<?> rtype = mt.returnType();
+        Class<?> rtc = MethodTypeImpl.canonicalize(rtype, howRet);
+        if (ptc == null && rtc == null) {
+            // It is already canonical.
+            return null;
+        }
+        // Find the erased version of the method type:
+        if (rtc == null)  rtc = rtype;
+        if (ptc == null)  ptc = ptypes;
+        return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true);
+    }
+
+    /** Canonicalize the given return or param type.
+     *  Return null if the type is already canonicalized.
+     */
+    static Class<?> canonicalize(Class<?> t, int how) {
+        Class<?> ct;
+        if (t == Object.class) {
+            // no change, ever
+        } else if (!t.isPrimitive()) {
+            switch (how) {
+                case UNWRAP:
+                    ct = Wrapper.asPrimitiveType(t);
+                    if (ct != t)  return ct;
+                    break;
+                case RAW_RETURN:
+                case ERASE:
+                    return Object.class;
+            }
+        } else if (t == void.class) {
+            // no change, usually
+            switch (how) {
+                case RAW_RETURN:
+                    return int.class;
+                case WRAP:
+                    return Void.class;
+            }
+        } else {
+            // non-void primitive
+            switch (how) {
+                case WRAP:
+                    return Wrapper.asWrapperType(t);
+                case INTS:
+                    if (t == int.class || t == long.class)
+                        return null;  // no change
+                    if (t == double.class)
+                        return long.class;
+                    return int.class;
+                case LONGS:
+                    if (t == long.class)
+                        return null;  // no change
+                    return long.class;
+                case RAW_RETURN:
+                    if (t == int.class || t == long.class ||
+                        t == float.class || t == double.class)
+                        return null;  // no change
+                    // everything else returns as an int
+                    return int.class;
+            }
+        }
+        // no change; return null to signify
+        return null;
+    }
+
+    /** Canonicalize each param type in the given array.
+     *  Return null if all types are already canonicalized.
+     */
+    static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
+        Class<?>[] cs = null;
+        for (int imax = ts.length, i = 0; i < imax; i++) {
+            Class<?> c = canonicalize(ts[i], how);
+            if (c != null) {
+                if (cs == null)
+                    cs = ts.clone();
+                cs[i] = c;
+            }
+        }
+        return cs;
+    }
+
+    public static Invokers invokers(Access token, MethodType type) {
+        Access.check(token);
+        Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
+        if (inv != null)  return inv;
+        inv = new Invokers(token, type);
+        METHOD_TYPE_FRIEND.setInvokers(type, inv);
+        return inv;
+    }
+
+    @Override
+    public String toString() {
+        return "Form"+erasedType;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/ToGeneric.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,1018 @@
+/*
+ * 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 sun.dyn;
+
+import java.dyn.JavaMethodHandle;
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodType;
+import java.dyn.NoAccessException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import sun.dyn.util.ValueConversions;
+import sun.dyn.util.Wrapper;
+
+/**
+ * Adapters which mediate between incoming calls which are not generic
+ * and outgoing calls which are.  Any call can be represented generically
+ * boxing up its arguments, and (on return) unboxing the return value.
+ * <p>
+ * A call is "generic" (in MethodHandle terms) if its MethodType features
+ * only Object arguments.  A non-generic call therefore features
+ * primitives and/or reference types other than Object.
+ * An adapter has types for its incoming and outgoing calls.
+ * The incoming call type is simply determined by the adapter's type
+ * (the MethodType it presents to callers).  The outgoing call type
+ * is determined by the adapter's target (a MethodHandle that the adapter
+ * either binds internally or else takes as a leading argument).
+ * (To stretch the term, adapter-like method handles may have multiple
+ * targets or be polymorphic across multiple call types.)
+ * @author jrose
+ */
+class ToGeneric {
+    // type for the incoming call (may be erased)
+    private final MethodType entryType;
+    // incoming type with primitives moved to the end and turned to int/long
+    private final MethodType rawEntryType;
+    // adapter for the erased type
+    private final Adapter adapter;
+    // entry point for adapter (Adapter mh, a...) => ...
+    private final MethodHandle entryPoint;
+    // permutation of arguments for primsAtEndType
+    private final int[] primsAtEndOrder;
+    // optional final argument list conversions (at least, invokes the target)
+    private final MethodHandle invoker;
+    // conversion which unboxes a primitive return value
+    private final MethodHandle returnConversion;
+
+    /** Compute and cache information common to all collecting adapters
+     *  that implement members of the erasure-family of the given erased type.
+     */
+    private ToGeneric(MethodType entryType) {
+        assert(entryType.erase() == entryType); // for now
+        // incoming call will first "forget" all reference types except Object
+        this.entryType = entryType;
+        MethodHandle invoker0 = MethodHandles.exactInvoker(entryType.generic());
+        MethodType rawEntryTypeInit;
+        Adapter ad = findAdapter(rawEntryTypeInit = entryType);
+        if (ad != null) {
+            // Immediate hit to exactly the adapter we want,
+            // with no monkeying around with primitive types.
+            this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false);
+            this.rawEntryType = rawEntryTypeInit;
+            this.adapter = ad;
+            this.entryPoint = ad.prototypeEntryPoint();
+            this.primsAtEndOrder = null;
+            this.invoker = invoker0;
+            return;
+        }
+
+        // next, it will reorder primitives after references
+        MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd();
+        // at the same time, it will "forget" all primitive types except int/long
+        this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType);
+        if (primsAtEndOrder != null) {
+            // reordering is required; build on top of a simpler ToGeneric
+            ToGeneric va2 = ToGeneric.of(primsAtEnd);
+            this.adapter = va2.adapter;
+            this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN,
+                    va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder);
+            // example: for entryType of (int,Object,Object), the reordered
+            // type is (Object,Object,int) and the order is {1,2,0},
+            // and putPAE is (mh,int0,obj1,obj2) => mh.invoke(obj1,obj2,int0)
+            if (true) throw new UnsupportedOperationException("NYI");
+            return;
+        }
+
+        // after any needed argument reordering, it will reinterpret
+        // primitive arguments according to their "raw" types int/long
+        MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts();
+        ad = findAdapter(rawEntryTypeInit = intsAtEnd);
+        if (ad == null) {
+            // Perhaps the adapter is available only for longs.
+            // If so, we can use it, but there will have to be a little
+            // more stack motion on each call.
+            MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs();
+            ad = findAdapter(rawEntryTypeInit = longsAtEnd);
+            if (ad == null) {
+                // If there is no statically compiled adapter,
+                // build one by means of dynamic bytecode generation.
+                ad = buildAdapterFromBytecodes(rawEntryTypeInit = intsAtEnd);
+            }
+        }
+        MethodHandle rawEntryPoint = ad.prototypeEntryPoint();
+        MethodType tepType = entryType.insertParameterType(0, ad.getClass());
+        this.entryPoint =
+            AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, rawEntryPoint);
+        if (this.entryPoint == null)
+            throw new UnsupportedOperationException("cannot retype to "+entryType
+                    +" from "+rawEntryPoint.type().dropParameterType(0));
+        this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false);
+        this.rawEntryType = rawEntryTypeInit;
+        this.adapter = ad;
+        this.invoker = makeRawArgumentFilter(invoker0,
+                rawEntryPoint.type().dropParameterType(0), entryType);
+    }
+
+    /** A generic argument list will be created by a call of type 'raw'.
+     *  The values need to be reboxed for to match 'cooked'.
+     *  Do this on the fly.
+     */
+    // TO DO: Use a generic argument converter in a different file
+    static MethodHandle makeRawArgumentFilter(MethodHandle invoker,
+            MethodType raw, MethodType cooked) {
+        MethodHandle filteredInvoker = null;
+        for (int i = 0, nargs = raw.parameterCount(); i < nargs; i++) {
+            Class<?> src = raw.parameterType(i);
+            Class<?> dst = cooked.parameterType(i);
+            if (src == dst)  continue;
+            assert(src.isPrimitive() && dst.isPrimitive());
+            if (filteredInvoker == null) {
+                filteredInvoker =
+                        AdapterMethodHandle.makeCheckCast(Access.TOKEN,
+                            invoker.type().generic(), invoker, 0, MethodHandle.class);
+                if (filteredInvoker == null)  throw new UnsupportedOperationException("NYI");
+            }
+            MethodHandle reboxer = ValueConversions.rebox(dst, false);
+            FilterGeneric gen = new FilterGeneric(filteredInvoker.type(), (short)(1+i), (short)1, 'R');
+            filteredInvoker = gen.makeInstance(reboxer, filteredInvoker);
+        }
+        if (filteredInvoker == null)  return invoker;
+        return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker);
+    }
+
+    /**
+     * Caller will be expecting a result from a call to {@code type},
+     * while the internal adapter entry point is rawEntryType.
+     * Also, the internal target method will be returning a boxed value,
+     * as an untyped object.
+     * <p>
+     * Produce a value converter which will be typed to convert from
+     * {@code Object} to the return value of {@code rawEntryType}, and will
+     * in fact ensure that the value is compatible with the return type of
+     * {@code type}.
+     */
+    private static MethodHandle computeReturnConversion(
+            MethodType type, MethodType rawEntryType, boolean mustCast) {
+        Class<?> tret = type.returnType();
+        Class<?> rret = rawEntryType.returnType();
+        if (mustCast || !tret.isPrimitive()) {
+            assert(!tret.isPrimitive());
+            assert(!rret.isPrimitive());
+            if (rret == Object.class && !mustCast)
+                return null;
+            return ValueConversions.cast(tret, false);
+        } else if (tret == rret) {
+            return ValueConversions.unbox(tret, false);
+        } else {
+            assert(rret.isPrimitive());
+            assert(tret == double.class ? rret == long.class : rret == int.class);
+            return ValueConversions.unboxRaw(tret, false);
+        }
+    }
+
+    Adapter makeInstance(MethodType type, MethodHandle genericTarget) {
+        genericTarget.getClass();  // check for NPE
+        MethodHandle convert = returnConversion;
+        if (primsAtEndOrder != null)
+            // reorder arguments passed to genericTarget, if primsAtEndOrder
+            throw new UnsupportedOperationException("NYI");
+        if (type == entryType) {
+            if (convert == null)  convert = ValueConversions.identity();
+            return adapter.makeInstance(entryPoint, invoker, convert, genericTarget);
+        }
+        // my erased-type is not exactly the same as the desired type
+        assert(type.erase() == entryType);  // else we are busted
+        if (convert == null)
+            convert = computeReturnConversion(type, rawEntryType, true);
+        // retype erased reference arguments (the cast makes it safe to do this)
+        MethodType tepType = type.insertParameterType(0, adapter.getClass());
+        MethodHandle typedEntryPoint =
+            AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, entryPoint);
+        return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget);
+    }
+
+    /** Build an adapter of the given type, which invokes genericTarget
+     *  on the incoming arguments, after boxing as necessary.
+     *  The return value is unboxed if necessary.
+     * @param type  the required type of the
+     * @param genericTarget the target, which must accept and return only Object values
+     * @return an adapter method handle
+     */
+    public static MethodHandle make(MethodType type, MethodHandle genericTarget) {
+        MethodType gtype = genericTarget.type();
+        if (type.generic() != gtype)
+            throw new IllegalArgumentException();
+        if (type == gtype)  return genericTarget;
+        return ToGeneric.of(type).makeInstance(type, genericTarget);
+    }
+
+    /** Return the adapter information for this type's erasure. */
+    static ToGeneric of(MethodType type) {
+        MethodTypeImpl form = MethodTypeImpl.of(type);
+        ToGeneric toGen = form.toGeneric;
+        if (toGen == null)
+            form.toGeneric = toGen = new ToGeneric(form.erasedType());
+        return toGen;
+    }
+
+    public String toString() {
+        return "ToGeneric"+entryType
+                +(primsAtEndOrder!=null?"[reorder]":"");
+    }
+
+    /* Create an adapter for the given incoming call type. */
+    static Adapter findAdapter(MethodType entryPointType) {
+        MethodTypeImpl form = MethodTypeImpl.of(entryPointType);
+        Class<?> rtype = entryPointType.returnType();
+        int argc = form.parameterCount();
+        int lac = form.longPrimitiveParameterCount();
+        int iac = form.primitiveParameterCount() - lac;
+        String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : "");
+        String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar());
+        String iname0 = "invoke_"+rawReturn;
+        String iname1 = "invoke";
+        String[] inames = { iname0, iname1 };
+        String cname0 = rawReturn + argc;
+        String cname1 = "A"       + argc;
+        String[] cnames = { cname1, cname1+intsAndLongs, cname0, cname0+intsAndLongs };
+        // e.g., D5I2, D5, L5I2, L5
+        for (String cname : cnames) {
+            Class<? extends Adapter> acls = Adapter.findSubClass(cname);
+            if (acls == null)  continue;
+            // see if it has the required invoke method
+            for (String iname : inames) {
+                MethodHandle entryPoint = null;
+                try {
+                    entryPoint = MethodHandleImpl.IMPL_LOOKUP.
+                                    findSpecial(acls, iname, entryPointType, acls);
+                } catch (NoAccessException ex) {
+                }
+                if (entryPoint == null)  continue;
+                Constructor<? extends Adapter> ctor = null;
+                try {
+                    // Prototype builder:
+                    ctor = acls.getDeclaredConstructor(MethodHandle.class);
+                } catch (NoSuchMethodException ex) {
+                } catch (SecurityException ex) {
+                }
+                if (ctor == null)  continue;
+                try {
+                    return ctor.newInstance(entryPoint);
+                } catch (IllegalArgumentException ex) {
+                } catch (InvocationTargetException ex) {
+                } catch (InstantiationException ex) {
+                } catch (IllegalAccessException ex) {
+                }
+            }
+        }
+        return null;
+    }
+
+    static Adapter buildAdapterFromBytecodes(MethodType entryPointType) {
+        throw new UnsupportedOperationException("NYI");
+    }
+
+    /**
+     * The invoke method takes some particular but unconstrained spread
+     * of raw argument types, and returns a raw return type (in L/I/J/F/D).
+     * Internally, it converts the incoming arguments uniformly into objects.
+     * This series of objects is then passed to the {@code target} method,
+     * which returns a result object.  This result is finally converted,
+     * via another method handle {@code convert}, which is responsible for
+     * converting the object result into the raw return value.
+     */
+    static abstract class Adapter extends JavaMethodHandle {
+        /*
+         * class X<<R,A...>> extends Adapter {
+         *   Object...=>Object target;
+         *   Object=>R convert;
+         *   R invoke(A... a...) = convert(invoker(target, a...)))
+         * }
+         */
+        protected final MethodHandle invoker;  // (MH, Object...) -> Object
+        protected final MethodHandle target;   // Object... -> Object
+        protected final MethodHandle convert;  // Object -> R
+
+        protected boolean isPrototype() { return target == null; }
+        /* Prototype constructor. */
+        protected Adapter(MethodHandle entryPoint) {
+            super(entryPoint);
+            this.invoker = null;
+            this.convert = entryPoint;
+            this.target = null;
+            assert(isPrototype());
+        }
+        protected MethodHandle prototypeEntryPoint() {
+            if (!isPrototype())  throw new InternalError();
+            return convert;
+        }
+
+        protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
+            super(entryPoint);
+            this.invoker = invoker;
+            this.convert = convert;
+            this.target = target;
+        }
+
+        /** Make a copy of self, with new fields. */
+        protected abstract Adapter makeInstance(MethodHandle entryPoint,
+                MethodHandle invoker, MethodHandle convert, MethodHandle target);
+        // { return new ThisType(entryPoint, convert, target); }
+
+        // Code to run when the arguments (<= 4) have all been boxed.
+        protected Object target()               { return invoker.<Object>invoke(target); }
+        protected Object target(Object a0)      { return invoker.<Object>invoke(target, a0); }
+        protected Object target(Object a0, Object a1)
+                                                { return invoker.<Object>invoke(target, a0, a1); }
+        protected Object target(Object a0, Object a1, Object a2)
+                                                { return invoker.<Object>invoke(target, a0, a1, a2); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3)
+                                                { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
+        /*
+        protected Object target_0(Object... av) { return invoker.<Object>invoke(target, av); }
+        protected Object target_1(Object a0, Object... av)
+                                                { return invoker.<Object>invoke(target, a0, (Object)av); }
+        protected Object target_2(Object a0, Object a1, Object... av)
+                                                { return invoker.<Object>invoke(target, a0, a1, (Object)av); }
+        protected Object target_3(Object a0, Object a1, Object a2, Object... av)
+                                                { return invoker.<Object>invoke(target, a0, a1, a2, (Object)av); }
+        protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
+                                                { return invoker.<Object>invoke(target, a0, a1, a2, a3, (Object)av); }
+        // */
+        // (For more than 4 arguments, generate the code in the adapter itself.)
+
+        // Code to run when the generic target has finished and produced a value.
+        protected Object return_L(Object res) { return convert.<Object>invoke(res); }
+        protected int    return_I(Object res) { return convert.<int   >invoke(res); }
+        protected long   return_J(Object res) { return convert.<long  >invoke(res); }
+        protected float  return_F(Object res) { return convert.<float >invoke(res); }
+        protected double return_D(Object res) { return convert.<double>invoke(res); }
+
+        static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
+        static {
+            String aname = Adapter.class.getName();
+            String sname = Adapter.class.getSimpleName();
+            if (!aname.endsWith(sname))  throw new InternalError();
+            CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
+        }
+        /** Find a sibing class of Adapter. */
+        static Class<? extends Adapter> findSubClass(String name) {
+            String cname = Adapter.CLASS_PREFIX + name;
+            try {
+                return Class.forName(cname).asSubclass(Adapter.class);
+            } catch (ClassNotFoundException ex) {
+                return null;
+            } catch (ClassCastException ex) {
+                return null;
+            }
+        }
+    }
+
+    /* generated classes follow this pattern:
+    static class A1 extends Adapter {
+        protected A1(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
+        protected Object target(Object a0)    { return invoker.<Object>invoke(target, a0); }
+        protected Object targetA1(Object a0) { return target(a0); }
+        protected Object targetA1(int    a0) { return target(a0); }
+        protected Object targetA1(long   a0) { return target(a0); }
+        protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(Object a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(Object a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(Object a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(Object a0) { return return_D(targetA1(a0)); }
+        protected Object invoke_L(int    a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(int    a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(int    a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(int    a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(int    a0) { return return_D(targetA1(a0)); }
+        protected Object invoke_L(long   a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(long   a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(long   a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(long   a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(long   a0) { return return_D(targetA1(a0)); }
+    }
+    // */
+
+/*
+: SHELL; n=ToGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
+//{{{
+import java.util.*;
+class genclasses {
+    static String[] TYPES = { "Object", "int   ", "long  ", "float ", "double" };
+    static String[] TCHARS = { "L",     "I",      "J",      "F",      "D",     "A" };
+    static String[][] TEMPLATES = { {
+        "@for@ arity=0..3   rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
+        "@for@ arity=4..5   rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
+        "@for@ arity=6..10  rcat<=2 nrefs<=99 nints=0   nlongs<=99",
+        "    //@each-cat@",
+        "    static class @cat@ extends Adapter {",
+        "        protected @cat@(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype",
+        "        protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
+        "        protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
+        "        protected Object target(@Ovav@)   { return invoker.<Object>invoke(target, @av@); }",
+        "        //@each-Tv@",
+        "        protected Object target@cat@(@Tvav@) { return target(@av@); }",
+        "        //@end-Tv@",
+        "        //@each-Tv@",
+        "        //@each-R@",
+        "        protected @R@ invoke_@Rc@(@Tvav@) { return return_@Rc@(target@cat@(@av@)); }",
+        "        //@end-R@",
+        "        //@end-Tv@",
+        "    }",
+    } };
+    enum VAR {
+        cat, R, Rc, Tv, av, Tvav, Ovav;
+        public final String pattern = "@"+toString().replace('_','.')+"@";
+        public String binding;
+        static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
+            int nargs = nrefs + nints + nlongs;
+            if (topLevel)
+                VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs);
+            VAR.R.binding = TYPES[rcat];
+            VAR.Rc.binding = TCHARS[rcat];
+            String[] Tv = new String[nargs];
+            String[] av = new String[nargs];
+            String[] Tvav = new String[nargs];
+            String[] Ovav = new String[nargs];
+            for (int i = 0; i < nargs; i++) {
+                int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2;
+                Tv[i] = TYPES[tcat];
+                av[i] = arg(i);
+                Tvav[i] = param(Tv[i], av[i]);
+                Ovav[i] = param("Object", av[i]);
+            }
+            VAR.Tv.binding = comma(Tv);
+            VAR.av.binding = comma(av);
+            VAR.Tvav.binding = comma(Tvav);
+            VAR.Ovav.binding = comma(Ovav);
+        }
+        static String arg(int i) { return "a"+i; }
+        static String param(String t, String a) { return t+" "+a; }
+        static String comma(String[] v) { return comma(v, ""); }
+        static String comma(String sep, String[] v) {
+            if (v.length == 0)  return "";
+            String res = sep+v[0];
+            for (int i = 1; i < v.length; i++)  res += ", "+v[i];
+            return res;
+        }
+        static String transform(String string) {
+            for (VAR var : values())
+                string = string.replaceAll(var.pattern, var.binding);
+            return string;
+        }
+    }
+    static String[] stringsIn(String[] strings, int beg, int end) {
+        return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
+    }
+    static String[] stringsBefore(String[] strings, int pos) {
+        return stringsIn(strings, 0, pos);
+    }
+    static String[] stringsAfter(String[] strings, int pos) {
+        return stringsIn(strings, pos, strings.length);
+    }
+    static int indexAfter(String[] strings, int pos, String tag) {
+        return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
+    }
+    static int indexBefore(String[] strings, int pos, String tag) {
+        for (int i = pos, end = strings.length; ; i++) {
+            if (i == end || strings[i].endsWith(tag))  return i;
+        }
+    }
+    static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS;
+    static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES;
+    static HashSet<String> done = new HashSet<String>();
+    public static void main(String... av) {
+        for (String[] template : TEMPLATES) {
+            int forLinesLimit = indexBefore(template, 0, "@each-cat@");
+            String[] forLines = stringsBefore(template, forLinesLimit);
+            template = stringsAfter(template, forLinesLimit);
+            for (String forLine : forLines)
+                expandTemplate(forLine, template);
+        }
+    }
+    static void expandTemplate(String forLine, String[] template) {
+        String[] params = forLine.split("[^0-9]+");
+        if (params[0].length() == 0)  params = stringsAfter(params, 1);
+        System.out.println("//params="+Arrays.asList(params));
+        int pcur = 0;
+        MIN_ARITY = Integer.valueOf(params[pcur++]);
+        MAX_ARITY = Integer.valueOf(params[pcur++]);
+        MAX_RCAT  = Integer.valueOf(params[pcur++]);
+        MAX_REFS  = Integer.valueOf(params[pcur++]);
+        MAX_INTS  = Integer.valueOf(params[pcur++]);
+        MAX_LONGS = Integer.valueOf(params[pcur++]);
+        if (pcur != params.length)  throw new RuntimeException("bad extra param: "+forLine);
+        if (MAX_RCAT >= TYPES.length)  MAX_RCAT = TYPES.length - 1;
+        ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length);
+        ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length);
+        for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) {
+            for (int rcat = 0; rcat <= MAX_RCAT; rcat++) {
+                expandTemplate(template, true, rcat, nargs, 0, 0);
+                if (ALL_ARG_TYPES)  break;
+                expandTemplateForPrims(template, true, rcat, nargs, 1, 1);
+                if (ALL_RETURN_TYPES)  break;
+            }
+        }
+    }
+    static String catstr(int rcat, int nrefs, int nints, int nlongs) {
+        int nargs = nrefs + nints + nlongs;
+        String cat = TCHARS[rcat] + nargs;
+        if (!ALL_ARG_TYPES)  cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs);
+        return cat;
+    }
+    static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) {
+        for (int isLong = 0; isLong <= 1; isLong++) {
+            for (int nprims = 1; nprims <= nargs; nprims++) {
+                int nrefs = nargs - nprims;
+                int nints = ((1-isLong) * nprims);
+                int nlongs = (isLong * nprims);
+                expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs);
+            }
+        }
+    }
+    static void expandTemplate(String[] template, boolean topLevel,
+                               int rcat, int nrefs, int nints, int nlongs) {
+        int nargs = nrefs + nints + nlongs;
+        if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS)  return;
+        VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+        if (topLevel && !done.add(VAR.cat.binding)) {
+            System.out.println("    //repeat "+VAR.cat.binding);
+            return;
+        }
+        for (int i = 0; i < template.length; i++) {
+            String line = template[i];
+            if (line.endsWith("@each-cat@")) {
+                // ignore
+            } else if (line.endsWith("@each-R@")) {
+                int blockEnd = indexAfter(template, i, "@end-R@");
+                String[] block = stringsIn(template, i+1, blockEnd-1);
+                for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++)
+                    expandTemplate(block, false, rcat1, nrefs, nints, nlongs);
+                VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+                i = blockEnd-1; continue;
+            } else if (line.endsWith("@each-Tv@")) {
+                int blockEnd = indexAfter(template, i, "@end-Tv@");
+                String[] block = stringsIn(template, i+1, blockEnd-1);
+                expandTemplate(block, false, rcat, nrefs, nints, nlongs);
+                expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1);
+                VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+                i = blockEnd-1; continue;
+            } else {
+                System.out.println(VAR.transform(line));
+            }
+        }
+    }
+}
+//}}} */
+//params=[0, 3, 4, 99, 99, 99]
+    static class A0 extends Adapter {
+        protected A0(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
+        protected Object target()   { return invoker.<Object>invoke(target); }
+        protected Object targetA0() { return target(); }
+        protected Object invoke_L() { return return_L(targetA0()); }
+        protected int    invoke_I() { return return_I(targetA0()); }
+        protected long   invoke_J() { return return_J(targetA0()); }
+        protected float  invoke_F() { return return_F(targetA0()); }
+        protected double invoke_D() { return return_D(targetA0()); }
+    }
+    static class A1 extends Adapter {
+        protected A1(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
+        protected Object target(Object a0)   { return invoker.<Object>invoke(target, a0); }
+        protected Object targetA1(Object a0) { return target(a0); }
+        protected Object targetA1(int    a0) { return target(a0); }
+        protected Object targetA1(long   a0) { return target(a0); }
+        protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(Object a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(Object a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(Object a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(Object a0) { return return_D(targetA1(a0)); }
+        protected Object invoke_L(int    a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(int    a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(int    a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(int    a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(int    a0) { return return_D(targetA1(a0)); }
+        protected Object invoke_L(long   a0) { return return_L(targetA1(a0)); }
+        protected int    invoke_I(long   a0) { return return_I(targetA1(a0)); }
+        protected long   invoke_J(long   a0) { return return_J(targetA1(a0)); }
+        protected float  invoke_F(long   a0) { return return_F(targetA1(a0)); }
+        protected double invoke_D(long   a0) { return return_D(targetA1(a0)); }
+    }
+    static class A2 extends Adapter {
+        protected A2(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); }
+        protected Object target(Object a0, Object a1)   { return invoker.<Object>invoke(target, a0, a1); }
+        protected Object targetA2(Object a0, Object a1) { return target(a0, a1); }
+        protected Object targetA2(Object a0, int    a1) { return target(a0, a1); }
+        protected Object targetA2(int    a0, int    a1) { return target(a0, a1); }
+        protected Object targetA2(Object a0, long   a1) { return target(a0, a1); }
+        protected Object targetA2(long   a0, long   a1) { return target(a0, a1); }
+        protected Object invoke_L(Object a0, Object a1) { return return_L(targetA2(a0, a1)); }
+        protected int    invoke_I(Object a0, Object a1) { return return_I(targetA2(a0, a1)); }
+        protected long   invoke_J(Object a0, Object a1) { return return_J(targetA2(a0, a1)); }
+        protected float  invoke_F(Object a0, Object a1) { return return_F(targetA2(a0, a1)); }
+        protected double invoke_D(Object a0, Object a1) { return return_D(targetA2(a0, a1)); }
+        protected Object invoke_L(Object a0, int    a1) { return return_L(targetA2(a0, a1)); }
+        protected int    invoke_I(Object a0, int    a1) { return return_I(targetA2(a0, a1)); }
+        protected long   invoke_J(Object a0, int    a1) { return return_J(targetA2(a0, a1)); }
+        protected float  invoke_F(Object a0, int    a1) { return return_F(targetA2(a0, a1)); }
+        protected double invoke_D(Object a0, int    a1) { return return_D(targetA2(a0, a1)); }
+        protected Object invoke_L(int    a0, int    a1) { return return_L(targetA2(a0, a1)); }
+        protected int    invoke_I(int    a0, int    a1) { return return_I(targetA2(a0, a1)); }
+        protected long   invoke_J(int    a0, int    a1) { return return_J(targetA2(a0, a1)); }
+        protected float  invoke_F(int    a0, int    a1) { return return_F(targetA2(a0, a1)); }
+        protected double invoke_D(int    a0, int    a1) { return return_D(targetA2(a0, a1)); }
+        protected Object invoke_L(Object a0, long   a1) { return return_L(targetA2(a0, a1)); }
+        protected int    invoke_I(Object a0, long   a1) { return return_I(targetA2(a0, a1)); }
+        protected long   invoke_J(Object a0, long   a1) { return return_J(targetA2(a0, a1)); }
+        protected float  invoke_F(Object a0, long   a1) { return return_F(targetA2(a0, a1)); }
+        protected double invoke_D(Object a0, long   a1) { return return_D(targetA2(a0, a1)); }
+        protected Object invoke_L(long   a0, long   a1) { return return_L(targetA2(a0, a1)); }
+        protected int    invoke_I(long   a0, long   a1) { return return_I(targetA2(a0, a1)); }
+        protected long   invoke_J(long   a0, long   a1) { return return_J(targetA2(a0, a1)); }
+        protected float  invoke_F(long   a0, long   a1) { return return_F(targetA2(a0, a1)); }
+        protected double invoke_D(long   a0, long   a1) { return return_D(targetA2(a0, a1)); }
+    }
+    static class A3 extends Adapter {
+        protected A3(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2)   { return invoker.<Object>invoke(target, a0, a1, a2); }
+        protected Object targetA3(Object a0, Object a1, Object a2) { return target(a0, a1, a2); }
+        protected Object targetA3(Object a0, Object a1, int    a2) { return target(a0, a1, a2); }
+        protected Object targetA3(Object a0, int    a1, int    a2) { return target(a0, a1, a2); }
+        protected Object targetA3(int    a0, int    a1, int    a2) { return target(a0, a1, a2); }
+        protected Object targetA3(Object a0, Object a1, long   a2) { return target(a0, a1, a2); }
+        protected Object targetA3(Object a0, long   a1, long   a2) { return target(a0, a1, a2); }
+        protected Object targetA3(long   a0, long   a1, long   a2) { return target(a0, a1, a2); }
+        protected Object invoke_L(Object a0, Object a1, Object a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(Object a0, Object a1, Object a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(Object a0, Object a1, Object a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(Object a0, Object a1, int    a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(Object a0, Object a1, int    a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(Object a0, Object a1, int    a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(Object a0, Object a1, int    a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(Object a0, Object a1, int    a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(Object a0, int    a1, int    a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(Object a0, int    a1, int    a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(Object a0, int    a1, int    a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(Object a0, int    a1, int    a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(Object a0, int    a1, int    a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(int    a0, int    a1, int    a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(int    a0, int    a1, int    a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(int    a0, int    a1, int    a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(int    a0, int    a1, int    a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(int    a0, int    a1, int    a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(Object a0, Object a1, long   a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(Object a0, Object a1, long   a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(Object a0, long   a1, long   a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(Object a0, long   a1, long   a2) { return return_D(targetA3(a0, a1, a2)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2) { return return_L(targetA3(a0, a1, a2)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2) { return return_I(targetA3(a0, a1, a2)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2) { return return_J(targetA3(a0, a1, a2)); }
+        protected float  invoke_F(long   a0, long   a1, long   a2) { return return_F(targetA3(a0, a1, a2)); }
+        protected double invoke_D(long   a0, long   a1, long   a2) { return return_D(targetA3(a0, a1, a2)); }
+    }
+//params=[4, 5, 2, 99, 99, 99]
+    static class A4 extends Adapter {
+        protected A4(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3)   { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, Object a1, Object a2, int    a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, Object a1, int    a2, int    a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, int    a1, int    a2, int    a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(int    a0, int    a1, int    a2, int    a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, Object a1, Object a2, long   a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, Object a1, long   a2, long   a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(Object a0, long   a1, long   a2, long   a3) { return target(a0, a1, a2, a3); }
+        protected Object targetA4(long   a0, long   a1, long   a2, long   a3) { return target(a0, a1, a2, a3); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, int    a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, int    a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, int    a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, Object a1, int    a2, int    a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, Object a1, int    a2, int    a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, Object a1, int    a2, int    a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, int    a1, int    a2, int    a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, int    a1, int    a2, int    a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, int    a1, int    a2, int    a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(int    a0, int    a1, int    a2, int    a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(int    a0, int    a1, int    a2, int    a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(int    a0, int    a1, int    a2, int    a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3) { return return_L(targetA4(a0, a1, a2, a3)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3) { return return_I(targetA4(a0, a1, a2, a3)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3) { return return_J(targetA4(a0, a1, a2, a3)); }
+    }
+    static class A5 extends Adapter {
+        protected A5(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int    a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, Object a2, int    a3, int    a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, int    a2, int    a3, int    a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, int    a1, int    a2, int    a3, int    a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(int    a0, int    a1, int    a2, int    a3, int    a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, Object a2, Object a3, long   a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, Object a2, long   a3, long   a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, Object a1, long   a2, long   a3, long   a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(Object a0, long   a1, long   a2, long   a3, long   a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object targetA5(long   a0, long   a1, long   a2, long   a3, long   a4) { return target(a0, a1, a2, a3, a4); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, int    a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, int    a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, int    a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, int    a3, int    a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, int    a3, int    a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, int    a3, int    a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, int    a2, int    a3, int    a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, int    a2, int    a3, int    a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, int    a2, int    a3, int    a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, int    a1, int    a2, int    a3, int    a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, int    a1, int    a2, int    a3, int    a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, int    a1, int    a2, int    a3, int    a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(int    a0, int    a1, int    a2, int    a3, int    a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(int    a0, int    a1, int    a2, int    a3, int    a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(int    a0, int    a1, int    a2, int    a3, int    a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
+    }
+//params=[6, 10, 2, 99, 0, 99]
+    static class A6 extends Adapter {
+        protected A6(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object targetA6(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return target(a0, a1, a2, a3, a4, a5); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
+    }
+    static class A7 extends Adapter {
+        protected A7(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object targetA7(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
+    }
+    static class A8 extends Adapter {
+        protected A8(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object targetA8(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
+    }
+    static class A9 extends Adapter {
+        protected A9(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object targetA9(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+    }
+    static class A10 extends Adapter {
+        protected A10(MethodHandle entryPoint) { super(entryPoint); }  // to build prototype
+        protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
+        protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); }
+        protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)   { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object targetA10(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, Object a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, Object a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, Object a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(Object a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected Object invoke_L(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected int    invoke_I(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+        protected long   invoke_J(long   a0, long   a1, long   a2, long   a3, long   a4, long   a5, long   a6, long   a7, long   a8, long   a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,297 @@
+/*
+ * 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 sun.dyn.anon;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Anonymous class loader.  Will load any valid classfile, producing
+ * a {@link Class} metaobject, without installing that class in the
+ * system dictionary.  Therefore, {@link Class#forName(String)} will never
+ * produce a reference to an anonymous class.
+ * <p>
+ * The access permissions of the anonymous class are borrowed from
+ * a <em>host class</em>.  The new class behaves as if it were an
+ * inner class of the host class.  It can access the host's private
+ * members, if the creator of the class loader has permission to
+ * do so (or to create accessible reflective objects).
+ * <p>
+ * When the anonymous class is loaded, elements of its constant pool
+ * can be patched to new values.  This provides a hook to pre-resolve
+ * named classes in the constant pool to other classes, including
+ * anonymous ones.  Also, string constants can be pre-resolved to
+ * any reference.  (The verifier treats non-string, non-class reference
+ * constants as plain objects.)
+ *  <p>
+ * Why include the patching function?  It makes some use cases much easier.
+ * Second, the constant pool needed some internal patching anyway,
+ * to anonymize the loaded class itself.  Finally, if you are going
+ * to use this seriously, you'll want to build anonymous classes
+ * on top of pre-existing anonymous classes, and that requires patching.
+ *
+ * <p>%%% TO-DO:
+ * <ul>
+ * <li>needs better documentation</li>
+ * <li>needs more security work (for safe delegation)</li>
+ * <li>needs a clearer story about error processing</li>
+ * <li>patch member references also (use ';' as delimiter char)</li>
+ * <li>patch method references to (conforming) method handles</li>
+ * </ul>
+ *
+ * @author jrose
+ * @author Remi Forax
+ * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
+ *      http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
+ */
+
+public class AnonymousClassLoader {
+    final Class<?> hostClass;
+
+    // Note: Do not refactor the calls to checkHostClass unless you
+    //       also adjust this constant:
+    private static int CHC_CALLERS = 3;
+
+    public AnonymousClassLoader() {
+        this.hostClass = checkHostClass(null);
+    }
+    public AnonymousClassLoader(Class<?> hostClass) {
+        this.hostClass = checkHostClass(hostClass);
+    }
+
+    private static Class<?> getTopLevelClass(Class<?> clazz) {
+      for(Class<?> outer = clazz.getDeclaringClass(); outer != null;
+          outer = outer.getDeclaringClass()) {
+        clazz = outer;
+      }
+      return clazz;
+    }
+
+    private static Class<?> checkHostClass(Class<?> hostClass) {
+        // called only from the constructor
+        // does a context-sensitive check on caller class
+        // CC[0..3] = {Reflection, this.checkHostClass, this.<init>, caller}
+        Class<?> caller = sun.reflect.Reflection.getCallerClass(CHC_CALLERS);
+
+        if (caller == null) {
+            // called from the JVM directly
+            if (hostClass == null)
+                return AnonymousClassLoader.class; // anything central will do
+            return hostClass;
+        }
+
+        if (hostClass == null)
+            hostClass = caller; // default value is caller itself
+
+        // anonymous class will access hostClass on behalf of caller
+        Class<?> callee = hostClass;
+
+        if (caller == callee)
+            // caller can always nominate itself to grant caller's own access rights
+            return hostClass;
+
+        // normalize caller and callee to their top-level classes:
+        caller = getTopLevelClass(caller);
+        callee = getTopLevelClass(callee);
+        if (caller == callee)
+            return caller;
+
+        ClassLoader callerCL = caller.getClassLoader();
+        if (callerCL == null) {
+            // caller is trusted code, so accept the proposed hostClass
+            return hostClass;
+        }
+
+        // %%% should do something with doPrivileged, because trusted
+        // code should have a way to execute on behalf of
+        // partially-trusted clients
+
+        // Does the caller have the right to access the private
+        // members of the callee?  If not, raise an error.
+        final int ACC_PRIVATE = 2;
+        try {
+            sun.reflect.Reflection.ensureMemberAccess(caller, callee, null, ACC_PRIVATE);
+        } catch (IllegalAccessException ee) {
+            throw new IllegalArgumentException(ee);
+        }
+
+        return hostClass;
+    }
+
+    public Class<?> loadClass(byte[] classFile) {
+        if (defineAnonymousClass == null) {
+            // no JVM support; try to fake an approximation
+            try {
+                return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
+            } catch (InvalidConstantPoolFormatException ee) {
+                throw new IllegalArgumentException(ee);
+            }
+        }
+        return loadClass(classFile, null);
+    }
+
+    public Class<?> loadClass(ConstantPoolPatch classPatch) {
+        if (defineAnonymousClass == null) {
+            // no JVM support; try to fake an approximation
+            return fakeLoadClass(classPatch);
+        }
+        Object[] patches = classPatch.patchArray;
+        // Convert class names (this late in the game)
+        // to use slash '/' instead of dot '.'.
+        // Java likes dots, but the JVM likes slashes.
+        for (int i = 0; i < patches.length; i++) {
+            Object value = patches[i];
+            if (value != null) {
+                byte tag = classPatch.getTag(i);
+                switch (tag) {
+                case ConstantPoolVisitor.CONSTANT_Class:
+                    if (value instanceof String) {
+                        if (patches == classPatch.patchArray)
+                            patches = patches.clone();
+                        patches[i] = ((String)value).replace('.', '/');
+                    }
+                    break;
+                case ConstantPoolVisitor.CONSTANT_Fieldref:
+                case ConstantPoolVisitor.CONSTANT_Methodref:
+                case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
+                case ConstantPoolVisitor.CONSTANT_NameAndType:
+                    // When/if the JVM supports these patches,
+                    // we'll probably need to reformat them also.
+                    // Meanwhile, let the class loader create the error.
+                    break;
+                }
+            }
+        }
+        return loadClass(classPatch.outer.classFile, classPatch.patchArray);
+    }
+
+    private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
+        try {
+            return (Class<?>)
+                defineAnonymousClass.invoke(unsafe,
+                                            hostClass, classFile, patchArray);
+        } catch (Exception ex) {
+            throwReflectedException(ex);
+            throw new RuntimeException("error loading into "+hostClass, ex);
+        }
+    }
+
+    private static void throwReflectedException(Exception ex) {
+        if (ex instanceof InvocationTargetException) {
+            Throwable tex = ((InvocationTargetException)ex).getTargetException();
+            if (tex instanceof Error)
+                throw (Error) tex;
+            ex = (Exception) tex;
+        }
+        if (ex instanceof RuntimeException) {
+            throw (RuntimeException) ex;
+        }
+    }
+
+    private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
+        // Implementation:
+        // 1. Make up a new name nobody has used yet.
+        // 2. Inspect the tail-header of the class to find the this_class index.
+        // 3. Patch the CONSTANT_Class for this_class to the new name.
+        // 4. Add other CP entries required by (e.g.) string patches.
+        // 5. Flatten Class constants down to their names, making sure that
+        //    the host class loader can pick them up again accurately.
+        // 6. Generate the edited class file bytes.
+        //
+        // Potential limitations:
+        // * The class won't be truly anonymous, and may interfere with others.
+        // * Flattened class constants might not work, because of loader issues.
+        // * Pseudo-string constants will not flatten down to real strings.
+        // * Method handles will (of course) fail to flatten to linkage strings.
+        if (true)  throw new UnsupportedOperationException("NYI");
+        Object[] cpArray;
+        try {
+            cpArray = classPatch.getOriginalCP();
+        } catch (InvalidConstantPoolFormatException ex) {
+            throw new RuntimeException(ex);
+        }
+        int thisClassIndex = classPatch.getParser().getThisClassIndex();
+        String thisClassName = (String) cpArray[thisClassIndex];
+        synchronized (AnonymousClassLoader.class) {
+            thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
+        }
+        classPatch.putUTF8(thisClassIndex, thisClassName);
+        byte[] classFile = null;
+        return unsafe.defineClass(null, classFile, 0, classFile.length,
+                                  hostClass.getClassLoader(),
+                                  hostClass.getProtectionDomain());
+    }
+    private static int fakeNameCounter = 99999;
+
+    // ignore two warnings on this line:
+    static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+    // preceding line requires that this class be on the boot class path
+
+    static private final Method defineAnonymousClass;
+    static {
+        Method dac = null;
+        Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
+        try {
+            dac = unsafeClass.getMethod("defineAnonymousClass",
+                                        Class.class,
+                                        byte[].class,
+                                        Object[].class);
+        } catch (Exception ee) {
+            dac = null;
+        }
+        defineAnonymousClass = dac;
+    }
+
+    private static void noJVMSupport() {
+        throw new UnsupportedOperationException("no JVM support for anonymous classes");
+    }
+
+
+    private static native Class<?> loadClassInternal(Class<?> hostClass,
+                                                     byte[] classFile,
+                                                     Object[] patchArray);
+
+    public static byte[] readClassFile(Class<?> templateClass) throws IOException {
+        String templateName = templateClass.getName();
+        int lastDot = templateName.lastIndexOf('.');
+        java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
+        java.net.URLConnection connection = url.openConnection();
+        int contentLength = connection.getContentLength();
+        if (contentLength < 0)
+            throw new IOException("invalid content length "+contentLength);
+
+        byte[] classFile = new byte[contentLength];
+        InputStream tcs = connection.getInputStream();
+        for (int fill = 0, nr; fill < classFile.length; fill += nr) {
+            nr = tcs.read(classFile, fill, classFile.length - fill);
+            if (nr < 0)
+                throw new IOException("premature end of file");
+        }
+        return classFile;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/anon/ConstantPoolParser.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,368 @@
+/*
+ * 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 sun.dyn.anon;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+
+import static sun.dyn.anon.ConstantPoolVisitor.*;
+
+/** A constant pool parser.
+ */
+public class ConstantPoolParser {
+    final byte[] classFile;
+    final byte[] tags;
+    final char[] firstHeader;  // maghi, maglo, minor, major, cplen
+
+    // these are filled in on first parse:
+    int endOffset;
+    char[] secondHeader;       // flags, this_class, super_class, intlen
+
+    // used to decode UTF8 array
+    private char[] charArray = new char[80];
+
+    /** Creates a constant pool parser.
+     * @param classFile an array of bytes containing a class.
+     * @throws InvalidConstantPoolFormatException if the header of the class has errors.
+     */
+    public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException {
+        this.classFile = classFile;
+        this.firstHeader = parseHeader(classFile);
+        this.tags = new byte[firstHeader[4]];
+    }
+
+    /** Create a constant pool parser by loading the bytecodes of the
+     *  class taken as argument.
+     *
+     * @param templateClass the class to parse.
+     *
+     * @throws IOException raised if an I/O occurs when loading
+     *  the bytecode of the template class.
+     * @throws InvalidConstantPoolFormatException if the header of the class has errors.
+     *
+     * @see #ConstantPoolParser(byte[])
+     * @see AnonymousClassLoader#readClassFile(Class)
+     */
+    public ConstantPoolParser(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
+        this(AnonymousClassLoader.readClassFile(templateClass));
+    }
+
+    /** Creates an empty patch to patch the class file
+     *  used by the current parser.
+     * @return a new class patch.
+     */
+    public ConstantPoolPatch createPatch() {
+        return new ConstantPoolPatch(this);
+    }
+
+    /** Report the tag of the indicated CP entry.
+     * @param index
+     * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc.
+     */
+    public byte getTag(int index) {
+        getEndOffset();  // trigger an exception if we haven't parsed yet
+        return tags[index];
+    }
+
+    /** Report the length of the constant pool. */
+    public int getLength() {
+        return firstHeader[4];
+    }
+
+    /** Report the offset, within the class file, of the start of the constant pool. */
+    public int getStartOffset() {
+        return firstHeader.length * 2;
+    }
+
+    /** Report the offset, within the class file, of the end of the constant pool. */
+    public int getEndOffset() {
+        if (endOffset == 0)
+            throw new IllegalStateException("class file has not yet been parsed");
+        return endOffset;
+    }
+
+    /** Report the CP index of this class's own name. */
+    public int getThisClassIndex() {
+        getEndOffset();   // provoke exception if not yet parsed
+        return secondHeader[1];
+    }
+
+    /** Report the total size of the class file. */
+    public int getTailLength() {
+        return classFile.length - getEndOffset();
+    }
+
+    /** Write the head (header plus constant pool)
+     *  of the class file to the indicated stream.
+     */
+    public void writeHead(OutputStream out) throws IOException {
+        out.write(classFile, 0, getEndOffset());
+    }
+
+    /** Write the head (header plus constant pool)
+     *  of the class file to the indicated stream,
+     *  incorporating the non-null entries of the given array
+     *  as patches.
+     */
+    void writePatchedHead(OutputStream out, Object[] patchArray) {
+        // this will be useful to partially emulate the class loader on old JVMs
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Write the tail (everything after the constant pool)
+     *  of the class file to the indicated stream.
+     */
+    public void writeTail(OutputStream out) throws IOException {
+        out.write(classFile, getEndOffset(), getTailLength());
+    }
+
+    private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException {
+        char[] result = new char[5];
+        ByteBuffer buffer = ByteBuffer.wrap(classFile);
+        for (int i = 0; i < result.length; i++)
+            result[i] = (char) getUnsignedShort(buffer);
+        int magic = result[0] << 16 | result[1] << 0;
+        if (magic != 0xCAFEBABE)
+            throw new InvalidConstantPoolFormatException("invalid magic number "+magic);
+        // skip major, minor version
+        int len = result[4];
+        if (len < 1)
+            throw new InvalidConstantPoolFormatException("constant pool length < 1");
+        return result;
+    }
+
+    /** Parse the constant pool of the class
+     *  calling a method visit* each time a constant pool entry is parsed.
+     *
+     *  The order of the calls to visit* is not guaranteed to be the same
+     *  than the order of the constant pool entry in the bytecode array.
+     *
+     * @param visitor
+     * @throws InvalidConstantPoolFormatException
+     */
+    public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
+        ByteBuffer buffer = ByteBuffer.wrap(classFile);
+        buffer.position(getStartOffset()); //skip header
+
+        Object[] values = new Object[getLength()];
+        try {
+            parseConstantPool(buffer, values, visitor);
+        } catch(BufferUnderflowException e) {
+            throw new InvalidConstantPoolFormatException(e);
+        }
+        if (endOffset == 0) {
+            endOffset = buffer.position();
+            secondHeader = new char[4];
+            for (int i = 0; i < secondHeader.length; i++) {
+                secondHeader[i] = (char) getUnsignedShort(buffer);
+            }
+        }
+        resolveConstantPool(values, visitor);
+    }
+
+    private char[] getCharArray(int utfLength) {
+        if (utfLength <= charArray.length)
+            return charArray;
+        return charArray = new char[utfLength];
+    }
+
+    private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
+        for (int i = 1; i < tags.length; ) {
+            byte tag = (byte) getUnsignedByte(buffer);
+            assert(tags[i] == 0 || tags[i] == tag);
+            tags[i] = tag;
+            switch (tag) {
+                case CONSTANT_Utf8:
+                    int utfLen = getUnsignedShort(buffer);
+                    String value = getUTF8(buffer, utfLen, getCharArray(utfLen));
+                    visitor.visitUTF8(i, CONSTANT_Utf8, value);
+                    tags[i] = tag;
+                    values[i++] = value;
+                    break;
+                case CONSTANT_Integer:
+                    visitor.visitConstantValue(i, tag, buffer.getInt());
+                    i++;
+                    break;
+                case CONSTANT_Float:
+                    visitor.visitConstantValue(i, tag, buffer.getFloat());
+                    i++;
+                    break;
+                case CONSTANT_Long:
+                    visitor.visitConstantValue(i, tag, buffer.getLong());
+                    i+=2;
+                    break;
+                case CONSTANT_Double:
+                    visitor.visitConstantValue(i, tag, buffer.getDouble());
+                    i+=2;
+                    break;
+
+                case CONSTANT_Class:    // fall through:
+                case CONSTANT_String:
+                    tags[i] = tag;
+                    values[i++] = new int[] { getUnsignedShort(buffer) };
+                    break;
+
+                case CONSTANT_Fieldref:           // fall through:
+                case CONSTANT_Methodref:          // fall through:
+                case CONSTANT_InterfaceMethodref: // fall through:
+                case CONSTANT_NameAndType:
+                    tags[i] = tag;
+                    values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) };
+                    break;
+                default:
+                    throw new AssertionError("invalid constant "+tag);
+            }
+        }
+    }
+
+    private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) {
+        // clean out the int[] values, which are temporary
+        for (int beg = 1, end = values.length-1, beg2, end2;
+             beg <= end;
+             beg = beg2, end = end2) {
+             beg2 = end; end2 = beg-1;
+             //System.out.println("CP resolve pass: "+beg+".."+end);
+             for (int i = beg; i <= end; i++) {
+                  Object value = values[i];
+                  if (!(value instanceof int[]))
+                      continue;
+                  int[] array = (int[]) value;
+                  byte tag = tags[i];
+                  switch (tag) {
+                      case CONSTANT_String:
+                          String stringBody = (String) values[array[0]];
+                          visitor.visitConstantString(i, tag, stringBody, array[0]);
+                          values[i] = null;
+                          break;
+                      case CONSTANT_Class: {
+                          String className = (String) values[array[0]];
+                          // use the external form favored by Class.forName:
+                          className = className.replace('/', '.');
+                          visitor.visitConstantString(i, tag, className, array[0]);
+                          values[i] = className;
+                          break;
+                      }
+                      case CONSTANT_NameAndType: {
+                          String memberName = (String) values[array[0]];
+                          String signature  = (String) values[array[1]];
+                          visitor.visitDescriptor(i, tag, memberName, signature,
+                                                  array[0], array[1]);
+                          values[i] = new String[] {memberName, signature};
+                          break;
+                      }
+                      case CONSTANT_Fieldref:           // fall through:
+                      case CONSTANT_Methodref:          // fall through:
+                      case CONSTANT_InterfaceMethodref: {
+                              Object className   = values[array[0]];
+                              Object nameAndType = values[array[1]];
+                              if (!(className instanceof String) ||
+                                  !(nameAndType instanceof String[])) {
+                                   // one more pass is needed
+                                   if (beg2 > i)  beg2 = i;
+                                   if (end2 < i)  end2 = i;
+                                   continue;
+                              }
+                              String[] nameAndTypeArray = (String[]) nameAndType;
+                              visitor.visitMemberRef(i, tag,
+                                  (String)className,
+                                  nameAndTypeArray[0],
+                                  nameAndTypeArray[1],
+                                  array[0], array[1]);
+                              values[i] = null;
+                          }
+                          break;
+                      default:
+                          continue;
+                }
+            }
+        }
+    }
+
+    private static int getUnsignedByte(ByteBuffer buffer) {
+        return buffer.get() & 0xFF;
+    }
+
+    private static int getUnsignedShort(ByteBuffer buffer) {
+        int b1 = getUnsignedByte(buffer);
+        int b2 = getUnsignedByte(buffer);
+        return (b1 << 8) + (b2 << 0);
+    }
+
+    private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException {
+      int utfLimit = buffer.position() + utfLen;
+      int index = 0;
+      while (buffer.position() < utfLimit) {
+          int c = buffer.get() & 0xff;
+          if (c > 127) {
+              buffer.position(buffer.position() - 1);
+              return getUTF8Extended(buffer, utfLimit, charArray, index);
+          }
+          charArray[index++] = (char)c;
+      }
+      return new String(charArray, 0, index);
+    }
+
+    private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException {
+        int c, c2, c3;
+        while (buffer.position() < utfLimit) {
+            c = buffer.get() & 0xff;
+            switch (c >> 4) {
+                case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+                    /* 0xxxxxxx*/
+                    charArray[index++] = (char)c;
+                    break;
+                case 12: case 13:
+                    /* 110x xxxx   10xx xxxx*/
+                    c2 = buffer.get();
+                    if ((c2 & 0xC0) != 0x80)
+                        throw new InvalidConstantPoolFormatException(
+                            "malformed input around byte " + buffer.position());
+                     charArray[index++] = (char)(((c  & 0x1F) << 6) |
+                                                  (c2 & 0x3F));
+                    break;
+                case 14:
+                    /* 1110 xxxx  10xx xxxx  10xx xxxx */
+                    c2 = buffer.get();
+                    c3 = buffer.get();
+                    if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
+                       throw new InvalidConstantPoolFormatException(
+                          "malformed input around byte " + (buffer.position()));
+                    charArray[index++] = (char)(((c  & 0x0F) << 12) |
+                                                ((c2 & 0x3F) << 6)  |
+                                                ((c3 & 0x3F) << 0));
+                    break;
+                default:
+                    /* 10xx xxxx,  1111 xxxx */
+                    throw new InvalidConstantPoolFormatException(
+                        "malformed input around byte " + buffer.position());
+            }
+        }
+        // The number of chars produced may be less than utflen
+        return new String(charArray, 0, index);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java	Tue May 05 22:40:09 2009 -0700
@@ -0,0 +1,503 @@
+/*
+ * 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 sun.dyn.anon;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import static sun.dyn.anon.ConstantPoolVisitor.*;
+
+/** A class and its patched constant pool.
+ *
+ *  This class allow to modify (patch) a constant pool
+ *  by changing the value of its entry.
+ *  Entry are referenced using index that can be get
+ *  by parsing the constant pool using
+ *  {@link ConstantPoolParser#parse(ConstantPoolVisitor)}.
+ *
+ * @see ConstantPoolVisitor
+ * @see ConstantPoolParser#createPatch()
+ */
+public class ConstantPoolPatch {
+    final ConstantPoolParser outer;
+    final Object[] patchArray;
+
+    ConstantPoolPatch(ConstantPoolParser outer) {
+        this.outer      = outer;
+        this.patchArray = new Object[outer.getLength()];
+    }
+
+    /** Create a {@link ConstantPoolParser} and
+     *  a {@link ConstantPoolPatch} in one step.
+     *  Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}.
+     *
+     * @param classFile an array of bytes containing a class.
+     * @see #ConstantPoolParser(Class)
+     */
+    public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException {
+        this(new ConstantPoolParser(classFile));
+    }
+
+    /** Create a {@link ConstantPoolParser} and
+     *  a {@link ConstantPoolPatch} in one step.
+     *  Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}.
+     *
+     * @param templateClass the class to parse.
+     * @see #ConstantPoolParser(Class)
+     */
+    public ConstantPoolPatch(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
+        this(new ConstantPoolParser(templateClass));
+    }
+
+
+    /** Creates a patch from an existing patch.
+     *  All changes are copied from that patch.
+     * @param patch a patch
+     *
+     * @see ConstantPoolParser#createPatch()
+     */
+    public ConstantPoolPatch(ConstantPoolPatch patch) {
+        outer      = patch.outer;
+        patchArray = patch.patchArray.clone();
+    }
+
+    /** Which parser built this patch? */
+    public ConstantPoolParser getParser() {
+        return outer;
+    }
+
+    /** Report the tag at the given index in the constant pool. */
+    public byte getTag(int index) {
+        return outer.getTag(index);
+    }
+
+    /** Report the current patch at the given index of the constant pool.
+     *  Null means no patch will be made.
+     *  To observe the unpatched entry at the given index, use
+     *  {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)}
+     */
+    public Object getPatch(int index) {
+        Object value = patchArray[index];
+        if (value == null)  return null;
+        switch (getTag(index)) {
+        case CONSTANT_Fieldref:
+        case CONSTANT_Methodref:
+        case CONSTANT_InterfaceMethodref:
+            if (value instanceof String)
+                value = stripSemis(2, (String) value);
+            break;
+        case CONSTANT_NameAndType:
+            if (value instanceof String)
+                value = stripSemis(1, (String) value);
+            break;
+        }
+        return value;
+    }
+
+    /** Clear all patches. */
+    public void clear() {
+        Arrays.fill(patchArray, null);
+    }
+
+    /** Clear one patch. */
+    public void clear(int index) {
+        patchArray[index] = null;
+    }
+
+    /** Produce the patches as an array. */
+    public Object[] getPatches() {
+        return patchArray.clone();
+    }
+
+    /** Produce the original constant pool as an array. */
+    public Object[] getOriginalCP() throws InvalidConstantPoolFormatException {
+        return getOriginalCP(0, patchArray.length, -1);
+    }
+
+    /** Walk the constant pool, applying patches using the given map.
+     *
+     * @param utf8Map Utf8 strings to modify, if encountered
+     * @param classMap Classes (or their names) to modify, if encountered
+     * @param valueMap Constant values to modify, if encountered
+     * @param deleteUsedEntries if true, delete map entries that are used
+     */
+    public void putPatches(final Map<String,String> utf8Map,
+                           final Map<String,Object> classMap,
+                           final Map<Object,Object> valueMap,
+                           boolean deleteUsedEntries) throws InvalidConstantPoolFormatException {
+        final HashSet<String> usedUtf8Keys;
+        final HashSet<String> usedClassKeys;
+        final HashSet<Object> usedValueKeys;
+        if (deleteUsedEntries) {
+            usedUtf8Keys  = (utf8Map  == null) ? null : new HashSet<String>();
+            usedClassKeys = (classMap == null) ? null : new HashSet<String>();
+            usedValueKeys = (valueMap == null) ? null : new HashSet<Object>();
+        } else {
+            usedUtf8Keys = null;
+            usedClassKeys = null;
+            usedValueKeys = null;
+        }
+
+        outer.parse(new ConstantPoolVisitor() {
+
+            @Override
+            public void visitUTF8(int index, byte tag, String utf8) {
+                putUTF8(index, utf8Map.get(utf8));
+                if (usedUtf8Keys != null)  usedUtf8Keys.add(utf8);
+            }
+
+            @Override
+            public void visitConstantValue(int index, byte tag, Object value) {
+                putConstantValue(index, tag, valueMap.get(value));
+                if (usedValueKeys != null)  usedValueKeys.add(value);
+            }
+
+            @Override
+            public void visitConstantString(int index, byte tag, String name, int nameIndex) {
+                if (tag == CONSTANT_Class) {
+                    putConstantValue(index, tag, classMap.get(name));
+                    if (usedClassKeys != null)  usedClassKeys.add(name);
+                } else {
+                    assert(tag == CONSTANT_String);
+                    visitConstantValue(index, tag, name);
+                }
+            }
+        });
+        if (usedUtf8Keys != null)   utf8Map.keySet().removeAll(usedUtf8Keys);
+        if (usedClassKeys != null)  classMap.keySet().removeAll(usedClassKeys);
+        if (usedValueKeys != null)  valueMap.keySet().removeAll(usedValueKeys);
+    }
+
+    Object[] getOriginalCP(final int startIndex,
+                           final int endIndex,
+                           final int tagMask) throws InvalidConstantPoolFormatException {
+        final Object[] cpArray = new Object[endIndex - startIndex];
+        outer.parse(new ConstantPoolVisitor() {
+
+            void show(int index, byte tag, Object value) {
+                if (index < startIndex || index >= endIndex)  return;
+                if (((1 << tag) & tagMask) == 0)  return;
+                cpArray[index - startIndex] = value;
+            }
+
+            @Override
+            public void visitUTF8(int index, byte tag, String utf8) {
+                show(index, tag, utf8);
+            }
+
+            @Override
+            public void visitConstantValue(int index, byte tag, Object value) {
+                assert(tag != CONSTANT_String);
+                show(index, tag, value);
+            }