--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth.patch Sat Aug 16 00:27:35 2008 -0700
@@ -0,0 +1,3323 @@
+diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/CallSite.java
+@@ -0,0 +1,75 @@
++/*
++ * Copyright 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
++ * 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;
++
++/**
++ * 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>
++ * FIXME: Make this into a concrete (but non-final) class.
++ * @author jrose
++ */
++public interface CallSite {
++ /**
++ * Report the current linkage state of the call site. (This is mutable.)
++ * @return the current linkage state of the call site
++ */
++ public MethodHandle getTarget();
++
++ /**
++ * Link or relink the call site, by setting its target method.
++ * @param target the new target, or null if it is to be unlinked
++ */
++ public void setTarget(MethodHandle target);
++
++ /**
++ * Report the class containing the call site. (This is immutable static context.)
++ * @return class containing the call site
++ */
++ Class callerClass();
++
++ /**
++ * Report the method name specified in the {@code invokedynamic} instruction. (This is immutable static context.)
++ * @return method name specified by the call site
++ */
++ String name();
++
++ /*
++ * Report the result and parameter types, derived from the invocation descriptor, and resolved
++ * against the calling class's class loader. (This is immutable static context.)
++ * @return method type specified by the call site
++ */
++ MethodType type();
++}
+diff --git a/src/share/classes/java/dyn/Dynamic.java b/src/share/classes/java/dyn/Dynamic.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/Dynamic.java
+@@ -0,0 +1,37 @@
++/*
++ * Copyright 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
++ * 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 for {@code invokedynamic} instructions.
++ * This type has no particular meaning as a class or interface supertype, and need never be implemented by any class.
++ * Logically, it denotes a dynamically typed reference to any object.
++ * As such it may be viewed as logically containing all methods on any of those types.
++ * @author jrose
++ */
++public class Dynamic {
++ // no methods
++}
+diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/Linkage.java
+@@ -0,0 +1,111 @@
++/*
++ * Copyright 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
++ * 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;
++
++/**
++ *
++ * @author jrose
++ */
++public class Linkage {
++ /**
++ * Register a bootstrap method for use for a given caller class.
++ * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}.
++ * <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.
++ */
++ void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ // FIXME: do not run this check if my caller and callerClass are package-mates.
++ security.checkPermission(new LinkagePermission("registerBootstrapMethod",callerClass));
++ }
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /** Determine if the caller class has declared or registered its own bootstrap method.
++ * If so, delegate this call to it. Otherwise, throw an IncompatibleClassChangeError.
++ */
++ public static
++ Object bootstrapInvokeDynamic(CallSite site, Object... receiverAndArguments) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * 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");
++ }
++}
+diff --git a/src/share/classes/java/dyn/LinkagePermission.java b/src/share/classes/java/dyn/LinkagePermission.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/LinkagePermission.java
+@@ -0,0 +1,111 @@
++/*
++ * Copyright 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
++ * 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 jrose
++ */
++
++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());
++ }
++}
+diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/MethodHandle.java
+@@ -0,0 +1,127 @@
++/*
++ * Copyright 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
++ * 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.dyn.emu.*;
++import java.dyn.impl.*;
++
++/**
++ * 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.
++ * <p>
++ * Every call to a method handle specifies an intended method type,
++ * which must exactly match the type of the method handle.
++ * The call looks within the receiver object for a method
++ * named <code>invoke</code> of the intended method type.
++ * The call fails with a linkage error if the method does not exist,
++ * even if there is an <code>invoke</code> method
++ * of a closely similar signature.
++ * <p>
++ * The receiver object must either be of type <code>MethodHandle</code>
++ * or else possess an <code>invoke</code> method in a public supertype
++ * of the receiver object. In other words, invocation of method handles
++ * is structurally typed, and will succeed as long as the receiver
++ * contains a public method of the correct name and type.
++ * <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 gets access 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>invokeinterface</code> instruction.
++ * The interface type must be <code>MethodHandle</code> and the method name
++ * must be <code>invoke</code>. The signature of the invocation must
++ * (after linking symbolic type names) 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.
++ * <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 can only be created directly by
++ * the JVM, or synthesized from bytecode that also is allowed to contain
++ * an <code>invokespecial</code> instruction to the same method.
++ *
++ * @see MethodType
++ * @see MethodHandles
++ * @author jrose
++ */
++public class MethodHandle /*<T extends MethodType>*/ extends MH {
++ // interface MethodHandle<T extends MethodType<R,A...>>
++ // { T type(); <R,A...> public R invoke(A...); }
++
++ /**
++ * 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; // inherited field
++ }
++
++ /**
++ * Subclasses may be in other packages, but must possess
++ * a token which they obtained from MH with a security check.
++ * @param token
++ */
++ protected MethodHandle(Access token, MethodType type) {
++ super(token, type);
++ }
++}
+diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/MethodHandles.java
+@@ -0,0 +1,752 @@
++/*
++ * Copyright 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
++ * 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.Field;
++import java.lang.reflect.Method;
++import java.util.ArrayList;
++import sun.reflect.Reflection;
++
++//import java.dyn.emu.*;
++import java.dyn.impl.*;
++
++/**
++ * 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 jrose
++ */
++public class MethodHandles {
++
++ private MethodHandles() { } // do not instantiate
++
++ private static final Access TOKEN = Access.getToken();
++
++ //// Method handle creation from ordinary methods.
++
++ /**
++ * 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 caller.
++ * @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, or null if no such method exists
++ */
++ public static
++ MethodHandle findStatic(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, null, type, false, callc);
++ }
++
++ /**
++ * 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</code>) prepended.
++ * The method and all its argument types must be accessible to the caller.
++ * <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</code> or <code>invokeinterface</code> 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, or null if no such method exists
++ */
++ public static
++ MethodHandle findVirtual(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, defc, type, true, callc);
++ }
++
++ /**
++ * Produce an early-bound method handle for a virtual method.
++ * The type of the method handle will be that of the method,
++ * with the receiver type (<code>defc</code>) prepended.
++ * The method 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</code> 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, or null if no such method exists
++ */
++ public static
++ MethodHandle findSpecial(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, defc, type, false, callc);
++ }
++
++ /**
++ * Make a direct method handle to <i>m</i>, if the current caller 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</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * If <i>m</i> is not public, do not share the resulting handle with untrusted callers.
++ * @param m the reflected method
++ * @return a method handle which can invoke the reflected method
++ */
++ public static
++ MethodHandle unreflect(Method m) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, m, true, callc);
++ }
++
++ /**
++ * Produce a method handle for a reflected method.
++ * It will bypass checks for overriding methods on the receiver,
++ * as if by the <code>invokespecial</code> instruction.
++ * The type of the method handle will be that of the method,
++ * with the receiver type prepended.
++ * If the method's <code>accessible</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller,
++ * as if <code>invokespecial</code> instruction were being linked.
++ * @param m the reflected method
++ * @return a method handle which can invoke the reflected method
++ */
++ public static
++ MethodHandle unreflectSpecial(Method m) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, m, false, callc);
++ }
++
++ /**
++ * 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</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * @param f the reflected field
++ * @return a method handle which can load values from the reflected field
++ */
++ public static
++ MethodHandle unreflectGetter(Field f) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findField(TOKEN, f, false, (Class)callc);
++ }
++
++ /**
++ * 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</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * @param f the reflected field
++ * @return a method handle which can store values into the reflected field
++ */
++ public static
++ MethodHandle unreflectSetter(Field f) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findField(TOKEN, f, true, (Class)callc);
++ }
++
++ /// method handle modification (creation from other method handles)
++
++ /**
++ * Return the given method handle unchanged, after ensuring that
++ * its type is equal to the given type.
++ * @param mh
++ * @param type
++ * @return the original method handle
++ */
++ static <M extends MethodHandle>
++ M castType(M mh, MethodType type) {
++ MethodType mhType = mh.type();
++ if (!type.equals(mhType))
++ throw new ClassCastException(mhType.toString());
++ return mh;
++ }
++
++ /**
++ * 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
++ Object checkValue(Class<?> T0, Class<?> T1, Object value)
++ throws ClassCastException
++ {
++ if (T0 == T1) {
++ // no conversion needed
++ return value;
++ }
++ boolean prim0 = T0.isPrimitive(), prim1 = T1.isPrimitive();
++ Class<?> TW;
++ if (!prim0) {
++ if (!prim1) {
++ return T1.cast(T0.cast(value));
++ }
++ // convert reference to primitive by unboxing
++ TW = Wrappers.asWrapperType(T0);
++ return T1.cast(TW.cast(value));
++ }
++ if (!prim1) {
++ // convert primitive to reference type by boxing
++ TW = Wrappers.asWrapperType(T1);
++ return TW.cast(T0.cast(value));
++ }
++ // convert primitive to primitive; this requires a real value change
++ if (value == null)
++ return Wrappers.zeroValue(T1);
++ // convert non-Number primitives to Integer:
++ if (value instanceof Character) {
++ char ch = (char) (Character) value;
++ value = Integer.valueOf(ch);
++ if (T1 == Integer.class)
++ return value;
++ } else if (value instanceof Boolean) {
++ boolean z = (boolean) (Boolean) value;
++ value = Integer.valueOf(z ? 1 : 0);
++ if (T1 == Integer.class)
++ return value;
++ }
++ Number numval = (Number) value;
++ switch (Wrappers.basicTypeChar(T1)) {
++ case 'Z': return (numval.intValue() != 0);
++ case 'B': return numval.byteValue();
++ case 'C': return (char) numval.intValue();
++ case 'S': return numval.shortValue();
++ case 'I': return numval.intValue();
++ case 'J': return numval.longValue();
++ case 'F': return numval.floatValue();
++ case 'D': return numval.doubleValue();
++ }
++ return null;
++ }
++
++ static
++ Object checkValue(Class<?> T1, Object value)
++ throws ClassCastException
++ {
++ return checkValue(T1, value.getClass(), value);
++ }
++
++ /**
++ * <strong>NOTE: This is an unimplemented API design.</strong>
++ * <p>
++ * Produce a method handle which calls the original method handle,
++ * after performing general-purpose argument list conversions.
++ * The resulting method handle is guaranteed to confess a type
++ * which is equal to the desired newType.
++ * <p>
++ * An <i>outgoing argument</i> is one which will be passed to the
++ * original method handle. An <i>incoming argument</i> is one which
++ * will be passed to the new method handle. The old and
++ * new method types are determined by the original method handle's
++ * <code>getType</code> operation and the <code>newType</code> parameter,
++ * respectively.
++ * <p>
++ * The arguments string must specify the data source for every outgoing
++ * argument. The string contains zero or more short char sequences
++ * called <i>argument descriptors</i>, each of which determines
++ * how the corresponding outgoing parameter is supplied with an incoming
++ * argument, how an extra check is made during the call, or how a return
++ * value is to be produced.
++ * <p>
++ * An argument descriptor must have one of the following forms:
++ * <ul>
++ * <li>$<i>N</i> — the <i>N</i>th incoming argument ($0 is first)
++ * <li>$<i>N</i>/<i>I</i> — the <i>I</i>th array element of $<i>N</i>
++ * <li>$V — the values argument passed to this method
++ * <li>$V/<i>I</i> — the <i>I</i>th array element of $V
++ * <li>!$<i>N</i>/<i>L</i> — Array length cutoff:
++ * The incoming array argument <i>N</i> must be exactly of length L.
++ * (If L is zero, the array may be null also.)
++ * <li>{<i>D...</i>} — This is an array argument descriptor;
++ * a sequence of one or more argument descriptors
++ * is collected into an array. The brackets may not be nested.
++ * <li>{<i>...</i>*$<i>N</i>} — An array argument
++ * specifier may end with a starred argument reference,
++ * meaning that it and all remaining arguments are included
++ * in the tail of the outgoing argument array.
++ * <li>{<i>...</i>*<i>D</i>/<i>I</i>} — An array argument
++ * specifier may end with a starred element reference,
++ * meaning that all remaining elements of the incoming argument
++ * or value array are included in the tail of the
++ * outgoing argument array. (As a limiting case,
++ * if <i>I</i> is the incoming array length, no additional
++ * elements are added to the outgoing array.)
++ * <li>$X0 — a zero or null of the expected argument type
++ * <li>$X<i>X</i> — an integer hexadecimal constant is passed
++ * <li>$N — the new method handle itself is passed
++ * <li>$M — the original method handle itself is passed
++ * <li>*<i>D</i> — The final argument descriptor may be
++ * starred if it is an incoming argument or element descriptor,
++ * meaning that all remaining outgoing arguments are
++ * taken from that argument (or element) onward.
++ * (E.g., "*$1" means pass all arguments except the first,
++ * and "*$V/0" means pass all elements of the value array.)
++ * <li>=<i>D</i> — An equal sign introduces an optional
++ * return descriptor. The <i>N</i>th incoming argument is saved
++ * and used as the final return value from the new method handle.
++ * Any argument descriptor can be used after the equal sign.
++ * This descriptor must come last, if it appears at all.
++ * <li><i>...</i>*<i>D</i>=<i>D</i> — Star and equal sign
++ * can appear together; in this case the return descriptor is last.
++ * <li>commas and whitespace are ignored before and after descriptors
++ * </ul>
++ * All values N, I, L must be decimal numerals in the range 0..255.
++ * For outgoing arrays, if L is zero, a constant zero-length array
++ * may be passed instead of a new array.
++ * <p>
++ * Any argument array can be spread or unspread, though the
++ * Java varargs convention treats only the final argument this way.
++ * Spreading and unspreading respects the element type of the
++ * affected array(s), performing element-by-element conversion
++ * if necessary.
++ * <p>
++ * There must be exactly enough argument descriptors (not counting
++ * a final return descriptor) to supply every
++ * outgoing argument to the old method handle.
++ * <p>
++ * If an equals sign is present, the following specifier is not for
++ * an outgoing argument, but rather for the ultimate return value
++ * produced by the new method handle. In that case any return
++ * value produced by the original method is discarded.
++ * (This may be used to force an adapted method handle to return
++ * a fixed value, or a selected argument, such as the receiver.)
++ * <p>
++ * Additional conversions are applied as needed to ensure that
++ * the outgoing argument types and final return type are respected.
++ * These value-oriented conversions perform casting, boxing,
++ * and unboxing, exactly as described in {@link #convertArguments}.
++ * <p>
++ * If an array is created (because a curly bracket '{' is present)
++ * the type of the new array is exactly that specified by the
++ * corresponding outgoing argument or return type.
++ *
++ * @param mh the method handle to invoke after the argument is prepended
++ * @param newType the expected type of the new method handle
++ * @param arguments descriptions of individual arguments to pass to mh
++ * @param values the argument to prepend
++ * @return a new method handle which converts the argument list,
++ * before calling the original method handle
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments, Object values) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The fourth and following arguments are collected into a values array
++ * and passed to the main overloading of {@link #adaptArguments}.
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments, Object... values) {
++ return adaptArguments(mh, newType, arguments, (Object) values);
++ }
++
++ /**
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The missing value argument defaults to null, which is passed to
++ * the main overloading of {@link #adaptArguments}.
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments) {
++ return adaptArguments(mh, newType, arguments, (Object) null);
++ }
++
++ /**
++ * <strong>NOTE: This is an unimplemented API design.</strong>
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The original type and new type must have the same number of
++ * arguments.
++ * The resulting method handle is guaranteed to confess a type
++ * which is equal to the desired new type.
++ * <p>
++ * If the original type and new type are equal, returns mh.
++ * <p>
++ * The following conversions are applied as needed both to
++ * arguments and return types. If T0 and T1 are differing
++ * old and new parameter types (or new and old return types),
++ * then one of the following conversions is applied if possible:
++ * <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 Java casting
++ * conversion (JLS 5.5) is applied, if one exists.
++ * <li>If T0 and T1 are primitives and one is boolean and the other
++ * is one of byte, short, char, or int, then zero and non-zero
++ * values are interconverted with false and true, respectively.
++ * (This follows the usage of the bytecode verifier.)
++ * <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, 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>
++ * @param mh the method handle to invoke after arguments are retyped
++ * @param newType the expected type of the new method handle
++ * @return
++ */
++ public static
++ MethodHandle convertArguments(MethodHandle mh, MethodType newType) {
++ MethodType oldType = mh.type();
++ if (oldType.equals(newType))
++ return mh;
++ return adaptArguments(mh, newType, "*$0");
++ }
++
++ /**
++ * 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 mh 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 mh, MethodType newType) {
++ MethodType oldType = mh.type();
++ int inargs = newType.parameterCount();
++ int outargs = oldType.parameterCount();
++ int spreadPos = inargs - 1;
++ int numSpread = (outargs - spreadPos);
++ if (spreadPos < 0 || numSpread < 0)
++ throw new IllegalArgumentException("wrong number of arguments");
++ StringBuilder arguments = new StringBuilder(inargs * 4 + 16);
++ // examples:
++ // new(T[]) => old(x,y,z) "!$0/3 *$0/0"
++ // new(a,T[]) => old(a,x,y) "$0 !$1/2 *$1/0"
++ // new(a,b,T[]) => old(a,b) "$0 $1 !$2/0"
++ for (int i = 0; i < spreadPos; i++) {
++ arguments.append("$").append(i);
++ }
++ arguments.append("!$").append(spreadPos).append("/").append(numSpread);
++ if (numSpread != 0) {
++ arguments.append("*$").append(spreadPos).append("/0");
++ }
++ return adaptArguments(mh, newType, arguments.toString());
++ }
++
++ /**
++ * 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.
++ * @param mh 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 mh, MethodType newType) {
++ MethodType oldType = mh.type();
++ int inargs = newType.parameterCount();
++ int outargs = oldType.parameterCount();
++ int collectPos = outargs - 1;
++ int numCollect = (inargs - collectPos);
++ if (collectPos < 0 || numCollect < 0)
++ throw new IllegalArgumentException("wrong number of arguments");
++ StringBuilder arguments = new StringBuilder(inargs * 4 + 16);
++ // examples:
++ // new(x,y,z) => old(T[]) "{*$0}"
++ // new(a,x,y) => old(a,T[]) "$0 {*$1}"
++ // new(a,b) => old(a,b,T[]) "$0 $1 {}"
++ for (int i = 0; i < collectPos; i++) {
++ arguments.append("$").append(i);
++ }
++ if (numCollect == 0)
++ arguments.append("{}");
++ else
++ arguments.append("{*$").append(collectPos).append("}");
++ return adaptArguments(mh, newType, arguments.toString());
++ }
++
++ /**
++ * Produce a method handle which calls the original method handle,
++ * after inserting the given argument as the first argument.
++ * The type of the new method handle will drop the first argument
++ * type from the original handle's type.
++ * <p>
++ * Equivalent to <code>insertArgument(mh, value, 0)</code>.
++ */
++ public static
++ MethodHandle insertArgument(MethodHandle mh, Object value) {
++ return insertArgument(mh, value, 0);
++ }
++
++ /**
++ * Produce a method handle which calls the original method handle,
++ * after appending the given argument as the final argument.
++ * The type of the new method handle will drop the last argument
++ * type from the original handle's type.
++ * <p>
++ * Equivalent to <code>insertArgument(mh, value, N)</code>,
++ * where <i>N</i> is the number of arguments to <i>mh</i>.
++ */
++ public static
++ MethodHandle appendArgument(MethodHandle mh, Object value) {
++ return insertArgument(mh, value, mh.type().parameterCount());
++ }
++
++ /**
++ * 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>mh</i>,
++ * meaning to insert the new argument as the first or last (respectively),
++ * or somewhere in between.
++ * @param mh the method handle to invoke after the argument is inserted
++ * @param value the argument to insert
++ * @param pos where to insert the argument (zero for the first)
++ * @return a new method handle which inserts an additional argument,
++ * before calling the original method handle
++ */
++ public static
++ MethodHandle insertArgument(MethodHandle mh, Object value, int pos) {
++ MethodType oldType = mh.type();
++ ArrayList<Class<?>> ptypes =
++ new ArrayList<Class<?>>(oldType.parameterList());
++ int outargs = oldType.parameterCount();
++ int inargs = outargs - 1;
++ if (pos < 0 || pos >= outargs)
++ throw new IllegalArgumentException("no argument type to append");
++ Class<?> valueType = ptypes.remove(pos);
++ value = checkValue(valueType, value);
++ MethodType newType = MethodType.make(oldType.returnType(), ptypes);
++ 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 = MH.bindReceiver(TOKEN, mh, value);
++ if (bmh != null) return bmh;
++ // else fall through to general adapter machinery
++ }
++ String arguments;
++ switch (pos) {
++ case 0: arguments = inargs == 0 ? "$V" : "$V*$0"; break;
++ case 1: arguments = inargs == 1 ? "$0$V" : "$0$V*$1"; break;
++ default:
++ StringBuilder sb = new StringBuilder(outargs * 4 + 16);
++ for (int i = 0; i < outargs; i++) {
++ if (i < pos) {
++ sb.append("$").append(i);
++ } else if (i == pos) {
++ sb.append("$V");
++ } else {
++ sb.append("*$").append(i-1);
++ break;
++ }
++ }
++ arguments = sb.toString();
++ }
++ return adaptArguments(mh, newType, arguments, value);
++ }
++
++ /**
++ * Produce a method handle which calls the original method handle,
++ * after dropping the given argument at the given position.
++ * The type of the new method handle will insert the given argument
++ * type, 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>mh</i>,
++ * meaning to drop the first or last argument (respectively),
++ * or an argument somewhere in between.
++ * @param mh the method handle to invoke after the argument is dropped
++ * @param valueType the type 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 dropArgument(MethodHandle mh, Class<?> valueType, int pos) {
++ MethodType oldType = mh.type();
++ ArrayList<Class<?>> ptypes =
++ new ArrayList<Class<?>>(oldType.parameterList());
++ int outargs = oldType.parameterCount();
++ int inargs = outargs + 1;
++ if (pos < 0 || pos >= inargs)
++ throw new IllegalArgumentException("no argument type to remove");
++ ptypes.add(pos, valueType);
++ MethodType newType = MethodType.make(oldType.returnType(), ptypes);
++ String arguments;
++ switch (pos) {
++ case 0: arguments = inargs == 0 ? "": "*$1"; break;
++ case 1: arguments = inargs == 1 ? "$0": "$0*$2"; break;
++ default:
++ if (pos == outargs) { arguments = "*$0"; break; }
++ StringBuilder sb = new StringBuilder(outargs * 4 + 16);
++ for (int i = 0; i < outargs; i++) {
++ if (i < pos) {
++ sb.append("$").append(i);
++ } else if (i > pos) {
++ sb.append("*$").append(i);
++ break;
++ }
++ }
++ arguments = sb.toString();
++ }
++ return adaptArguments(mh, newType, arguments);
++ }
++
++ /// standard method handles
++
++ /**
++ * Identity function.
++ * @param x an arbitrary reference value
++ * @return the same value x
++ */
++ public static <T>
++ T identity(T x) {
++ return x;
++ }
++
++ /**
++ * A method handle for {@link identity}
++ */
++ public static
++ MethodHandle identityMethod() {
++ if (IDENTITY == null)
++ IDENTITY = findStatic(MethodHandle.class, "identity", IDENTITY_TYPE);
++ return IDENTITY;
++ }
++ private static
++ MethodHandle IDENTITY;
++ private static final
++ MethodType IDENTITY_TYPE = MethodType.make(Object.class, Object.class);
++
++ /**
++ * Empty function.
++ */
++ public static
++ void empty() {
++ }
++
++ /**
++ * A method handle for {@link empty}
++ */
++ public static
++ MethodHandle emptyMethod() {
++ if (EMPTY == null)
++ EMPTY = findStatic(MethodHandle.class, "empty", EMPTY_TYPE);
++ return EMPTY;
++ }
++ private static
++ MethodHandle EMPTY;
++ private static final
++ MethodType EMPTY_TYPE = MethodType.make(void.class);
++}
+diff --git a/src/share/classes/java/dyn/MethodType.java b/src/share/classes/java/dyn/MethodType.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/MethodType.java
+@@ -0,0 +1,553 @@
++/*
++ * Copyright 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
++ * 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.Method;
++import java.lang.reflect.Modifier;
++import java.util.ArrayList;
++import java.util.Arrays;
++import java.util.Collections;
++import java.util.HashMap;
++import java.util.List;
++
++/**
++ * 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, plus the varargs bit.
++ * <p>
++ * This type can be created only by factory methods, which manage interning.
++ *
++ * @author jrose
++ */
++public final
++class MethodType {
++ final Class<?> rtype;
++ final Class<?>[] ptypes;
++ MethodTypeForm form; // erased form, plus cached data about primitives
++ MethodType wrapAlt; // alternative wrapped/unwrapped version
++
++ private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean varargs) {
++ this.rtype = rtype;
++ this.ptypes = ptypes;
++ if (!varargs) {
++ this.form = MethodTypeForm.FAKE[0];
++ } else {
++ this.form = MethodTypeForm.FAKE[1];
++ checkVarargs();
++ }
++ assert(this.isVarArgs() == varargs);
++ }
++
++ private void checkVarargs() {
++ if (ptypes.length == 0 || !ptypes[ptypes.length-1].isArray())
++ throw new IllegalArgumentException("not varargs: "+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
++ */
++ public static
++ MethodType make(Class<?> rtype, Class<?>[] ptypes) {
++ return makeImpl(rtype, ptypes, false, false);
++ }
++
++ /** Find or create an instance of the given method type.
++ * @param rtype the return type
++ * @param ptypes the parameter types
++ * @param varargs whether the method type will be varargs
++ * @return the interned method type with the given parts
++ * @throws IllegalArgumentException if varargs is true and the last parameter type is not an array
++ */
++ public static
++ MethodType make(Class<?> rtype, Class<?>[] ptypes, boolean varargs) {
++ return makeImpl(rtype, ptypes, varargs, false);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}. */
++ public static
++ MethodType make(Class<?> rtype, List<Class<?>> ptypes) {
++ return makeImpl(rtype, ptypes.toArray(NO_PTYPES), false, true);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}. */
++ public static
++ MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
++ return makeImpl(rtype, append(ptype0, ptypes), false, 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, false, 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 }, false, 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, false, true);
++ }
++
++ /**
++ * Sole factory method to find or create an interned method type.
++ * @param rtype desired return type
++ * @param ptypes desired parameter types
++ * @param varargs whether the method type will be varargs
++ * @param trusted whether the ptypes can be used without cloning
++ * @return the unique method type of the desired structure
++ */
++ static
++ MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean varargs, boolean trusted) {
++ MethodType mt1 = new MethodType(rtype, ptypes, varargs);
++ MethodType mt0;
++ synchronized (internTable) {
++ mt0 = internTable.get(mt1);
++ if (mt0 != null)
++ return mt0;
++ }
++ if (!trusted)
++ // defensively copy the array passed in by the user
++ ptypes = ptypes.clone();
++ // promote the object to the Real Thing, and reprobe
++ mt1.form = MethodTypeForm.findForm(mt1, varargs);
++ assert(mt1.isVarArgs() == varargs);
++ synchronized (internTable) {
++ mt0 = internTable.get(mt1);
++ if (mt0 != null)
++ return mt0;
++ internTable.put(mt1, mt1);
++ }
++ return mt1;
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ * Find or create an instance (interned) of the given method type.
++ * <p>
++ * <em>Note:</em> Since method handles are created in the system class loader,
++ * this routine will attempt to install class loader constraints
++ * between the system loader and the given loader, for each name
++ * found in the signature. If these constraints cannot be created,
++ * this routine will throw a linkage error.
++ * @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
++ */
++ public static MethodType make(String bytecodeSignature, ClassLoader loader) {
++ if (loader == null)
++ loader = ClassLoader.getSystemClassLoader();
++ String str = bytecodeSignature;
++ int[] i = {0};
++ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
++ if (i[0] < str.length() && str.charAt(i[0]) == '(') {
++ ++i[0]; // skip '('
++ while (i[0] < str.length() && str.charAt(i[0]) != ')') {
++ Class<?> pt = parseSig(str, i, loader);
++ if (pt == null || pt == void.class)
++ parseError(str, "bad argument type");
++ ptypes.add(pt);
++ }
++ ++i[0]; // skip ')'
++ }
++ Class<?> rtype = parseSig(str, i, loader);
++ if (rtype == null || i[0] != str.length())
++ parseError(str, "bad return type");
++ return make(rtype, ptypes);
++ }
++
++ /** Create a bytecode signature representation of the type.
++ * @return the bytecode signature representation
++ */
++ public String toBytecodeString() {
++ StringBuilder sb = new StringBuilder();
++ sb.append('(');
++ for (Class<?> pt : ptypes)
++ unparseSig(pt, sb);
++ sb.append(')');
++ unparseSig(rtype, sb);
++ return sb.toString();
++ }
++
++ static private void parseError(String str, String msg) {
++ throw new IllegalArgumentException("bad signature: "+str+": "+msg);
++ }
++
++ static private Class<?> parseSig(String str, int[] i, ClassLoader loader) {
++ if (i[0] == str.length()) return null;
++ char c = str.charAt(i[0]++);
++ if (c == 'L') {
++ int beg = i[0], end = str.indexOf(';', beg);
++ if (end < 0) return null;
++ i[0] = end+1;
++ String name = str.substring(beg, end).replace('/', '.');
++ try {
++ // FIXME: Need loader constraints here?
++ return loader.loadClass(name);
++ } catch (ClassNotFoundException ex) {
++ parseError(str, ex.toString());
++ return null;
++ }
++ } else if (c == '[') {
++ Class<?> t = parseSig(str, i, loader);
++ if (t != null)
++ t = java.lang.reflect.Array.newInstance(t, 0).getClass();
++ return t;
++ } else {
++ return Wrappers.basicTypeFromChar(c);
++ }
++ }
++
++ private void unparseSig(Class<?> t, StringBuilder sb) {
++ char c = Wrappers.basicTypeChar(t);
++ if (c != 'L') {
++ sb.append(c);
++ } else {
++ boolean lsemi = (!t.isArray());
++ if (lsemi) sb.append('L');
++ sb.append(t.getName().replace('.', '/'));
++ if (lsemi) sb.append(';');
++ }
++ }
++
++
++ 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
++ * @return a totally generic method type, given only its count of parameters and varargs.
++ */
++ 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, varargs, true);
++ if (ootIndex < objectOnlyTypes.length) {
++ objectOnlyTypes[ootIndex] = mt; // cache it here also!
++ }
++ return mt;
++ }
++
++ /**
++ * Convenience method for {@link #makeGeneric(int, boolean)}, defaulting {@code varargs} to false.
++ */
++ public static
++ MethodType makeGeneric(int objectArgCount) {
++ return makeGeneric(objectArgCount, false);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[], boolean)}.
++ * @param refm a reflective method
++ * @return the type (as for a {@link MethodHandle}) of that method
++ */
++ public static
++ MethodType make(Method refm) {
++ Class<?> rt = refm.getReturnType();
++ Class<?>[] pts = refm.getParameterTypes();
++ if (!Modifier.isStatic(refm.getModifiers()))
++ // implicit initial parameter is the receiver type
++ pts = append(refm.getDeclaringClass(), pts);
++ return makeImpl(rt, pts, refm.isVarArgs(), true);
++ }
++
++ static Class<?>[] append(Class<?> pt0, Class<?>... pts) {
++ Class<?>[] res = new Class<?>[1+pts.length];
++ res[0] = pt0;
++ System.arraycopy(pts, 0, res, 1, pts.length);
++ return res;
++ }
++
++ /** 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 change
++ */
++ public MethodType newParameterType(int num, Class<?> nptype) {
++ if (parameterType(num) == nptype) return this;
++ Class<?>[] nptypes = ptypes.clone();
++ nptypes[num] = nptype;
++ return makeImpl(rtype, nptypes, isVarArgs(), 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 newReturnType(Class<?> nrtype) {
++ if (returnType() == nrtype) return this;
++ return makeImpl(nrtype, ptypes, isVarArgs(), true);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[], boolean)}.
++ * @param varargs a new setting of the varargs flag
++ * @return the same type, except with the varargs change
++ * @throws IllegalArgumentException if varargs is true and the last parameter type is not an array
++ */
++ public MethodType newVarArgs(boolean varargs) {
++ if (isVarArgs() == varargs) return this;
++ return makeImpl(rtype, ptypes, varargs, 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.primCounts != 0;
++ }
++
++ /** 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.erase;
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ * Erase all reference types to Object, and all primitive types to wrappers.
++ * @return a version of the original type with references erase and primitives wrapped
++ */
++ public MethodType eraseWrap() {
++ return form.wrap;
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ * Convert all types to their Object.
++ * @return a version of the original type with all types replaced
++ * @see #makeGeneric(int)
++ */
++ public MethodType generic() {
++ return form.wrap.erase();
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ * Convert all primitive types to their corresponding wrapper types.
++ * @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.
++ * @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 = MethodTypeForm.canonType(pt, MethodTypeForm.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 = MethodTypeForm.canonType(wt, MethodTypeForm.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;
++ }
++ /** @return whether this is a varargs type */
++ public boolean isVarArgs() {
++ return form.varargs;
++ }
++
++ /**
++ * 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,
++ * and agree on their varargs flag.
++ * @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
++ && this.isVarArgs() == that.isVarArgs()
++ && 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, plus an additional void type if varargs is set.
++ * @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();
++ if (isVarArgs())
++ hashCode = 31*hashCode + void.class.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.
++ * The last argument type name is followed by "..."
++ * if the type is vararags.
++ * <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("(");
++ int vanum = isVarArgs() ? ptypes.length-1 : -1 ;
++ for (int i = 0; i < ptypes.length; i++) {
++ if (i > 0) sb.append(",");
++ if (i == vanum) {
++ putName(sb, ptypes[i].getComponentType());
++ sb.append("...");
++ break;
++ }
++ 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--;
++ }
++ }
++}
+diff --git a/src/share/classes/java/dyn/MethodTypeForm.java b/src/share/classes/java/dyn/MethodTypeForm.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/MethodTypeForm.java
+@@ -0,0 +1,218 @@
++/*
++ * Copyright 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
++ * 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.dyn.emu.*;
++import java.dyn.impl.*;
++
++/**
++ * 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 jrose
++ */
++class MethodTypeForm extends MTForm {
++ final int argCounts; // byte-packed slot & value counts
++ final int primCounts; // byte-packed prim & double counts
++ final boolean varargs;
++ final MethodType erase;
++ final MethodType wrap;
++
++ private static final Access TOKEN = Access.getToken();
++
++ private MethodTypeForm(MethodType erase, boolean varargs) {
++ super(TOKEN);
++ this.erase = erase;
++ this.varargs = varargs;
++ MethodType wt = canonType(erase, WRAP);
++ this.wrap = (wt == null) ? erase : wt;
++
++ int ptypeCount = erase.ptypes.length;
++ int pslotCount = ptypeCount; // temp. estimate
++ int rtypeCount = 1; // temp. estimate
++ int rslotCount = 1;
++
++ assert(varargs == (ptypeCount != 0 && erase.ptypes[ptypeCount-1].isArray()));
++
++ // Walk the argument types, looking for primitives.
++ if (wt != null) {
++ int pac = 0, lac = 0, prc = 0, lrc = 0;
++ Class<?> epts[] = erase.ptypes;
++ for (int i = 0; i < epts.length; i++) {
++ Class<?> pt = epts[i];
++ if (pt != Object.class) {
++ assert(pt.isPrimitive());
++ ++pac;
++ if (pt == long.class || pt == double.class)
++ ++lac;
++ }
++ }
++ pslotCount += lac; // #slots = #args + #longs
++ Class<?> rt = erase.rtype;
++ if (rt != Object.class) {
++ ++prc; // even void.class counts as a prim here
++ if (rt == long.class || rt == double.class)
++ ++lrc;
++ // adjust #slots, #args
++ if (rt == void.class)
++ rtypeCount = rslotCount = 0;
++ else
++ rslotCount += lrc;
++ }
++ this.primCounts = (lrc << 24) | (prc << 16) | (lac << 8) | pac;
++ } else {
++ this.primCounts = 0;
++ }
++ this.argCounts = (rslotCount << 24) | (rtypeCount << 16) | (pslotCount << 8) | ptypeCount;
++
++ if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments");
++
++ // Allow lower layer to initialize other derived information.
++ super.init(erase, parameterSlotCount());
++ }
++
++ // used only for bootstrapping:
++ static final MethodTypeForm[] FAKE = {
++ new MethodTypeForm(false), new MethodTypeForm(true)
++ };
++ // used only for making bootstrapping fakes:
++ private MethodTypeForm(boolean varargs) {
++ super(TOKEN);
++ this.varargs = varargs;
++ primCounts = argCounts = -1;
++ erase = wrap = null;
++ }
++
++ int parameterCount() { // # outgoing values
++ return argCounts & 0xFF;
++ }
++ int parameterSlotCount() { // # outgoing interpreter slots
++ return (argCounts >> 8) & 0xFF;
++ }
++ int returnCount() { // = 0 (V), or 1
++ return (argCounts >> 16) & 0xFF;
++ }
++ int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
++ return (argCounts >> 24) & 0xFF;
++ }
++ int primitiveParameterCount() {
++ return primCounts & 0xFF;
++ }
++ int longPrimitiveParameterCount() {
++ return (primCounts >> 8) & 0xFF;
++ }
++ int primitiveReturnCount() { // = 0 (obj), or 1
++ return (primCounts >> 16) & 0xFF;
++ }
++ int longPrimitiveReturnCount() { // = 1 (J/D), or 0
++ return (primCounts >> 24) & 0xFF;
++ }
++
++ static final int ERASE = 1, WRAP = 2, UNWRAP = 4, ARGS_ONLY = 8, KEEP_VARARG = 16;
++
++ static MethodTypeForm findForm(MethodType mt, boolean varargs) {
++ MethodType erased = canonType(mt, ERASE | (varargs ? KEEP_VARARG : 0));
++ if (erased == null) {
++ // It is already erased. Make a new MethodTypeForm.
++ return new MethodTypeForm(mt, varargs);
++ } else {
++ // Share the MethodTypeForm with the erased version.
++ return erased.form;
++ }
++ }
++
++ /** Canonicalize the types in the given method type.
++ * If any types change, intern the new type, and return it.
++ * Otherwise return null.
++ */
++ static MethodType canonType(MethodType mt, int how) {
++ Class<?>[] ptc = MethodTypeForm.canonTypes(mt.ptypes, how);
++ Class<?> rtc = null;
++ if ((how & ARGS_ONLY) == 0)
++ rtc = MethodTypeForm.canonType(mt.rtype, how);
++ if (ptc == null && rtc == null) {
++ // It is already canonical.
++ return null;
++ }
++ // Find the erased version of the method type:
++ if (rtc == null) rtc = mt.rtype;
++ if (ptc == null) ptc = mt.ptypes;
++ return MethodType.makeImpl(rtc, ptc, mt.isVarArgs(), true);
++ }
++
++ /** Canonicalize the given return or param type.
++ * Return null if the type is already canonicalized.
++ */
++ static Class<?> canonType(Class<?> t, int how) {
++ if (t == Object.class) {
++ // no change, ever
++ } else if (!t.isPrimitive()) {
++ if ((how & UNWRAP) != 0) {
++ Class<?> pt = Wrappers.asPrimitiveType(t);
++ if (pt != t)
++ return pt;
++ }
++ if ((how & ERASE) != 0)
++ return Object.class;
++ } else {
++ if ((how & WRAP) != 0) {
++ if ((how & ERASE) != 0)
++ return Object.class;
++ return Wrappers.asWrapperType(t);
++ }
++ }
++ // 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<?>[] canonTypes(Class<?>[] ts, int how) {
++ Class<?>[] cs = null;
++ for (int imax = ts.length, i = 0; i < imax; i++) {
++ Class<?> c = canonType(ts[i], how);
++ if (c != null) {
++ if ((how & KEEP_VARARG) != 0) {
++ // if this is a final 'vararg', stop canonicalizing now
++ if (i+1 == imax && ts[i].isArray()) break;
++ }
++ if (cs == null)
++ cs = ts.clone();
++ cs[i] = c;
++ }
++ }
++ return cs;
++ }
++
++}
+diff --git a/src/share/classes/java/dyn/Wrappers.java b/src/share/classes/java/dyn/Wrappers.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/Wrappers.java
+@@ -0,0 +1,121 @@
++/*
++ * Copyright 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
++ * 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.HashMap;
++
++public class Wrappers {
++
++ private Wrappers() { } // cannot instantiate
++
++ public static Class<?> asWrapperType(Class<?> parameterType) {
++ if (!parameterType.isPrimitive()) {
++ return parameterType;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(parameterType);
++ assert (memo != null);
++ return (Class<?>) memo[0];
++ }
++
++ public static Class<?> asPrimitiveType(Class<?> parameterType) {
++ if (parameterType.isPrimitive()) {
++ return parameterType;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(parameterType);
++ if (memo == null) {
++ return parameterType;
++ }
++ return (Class<?>) memo[1];
++ }
++
++ public static char basicTypeChar(Class<?> parameterType) {
++ if (!parameterType.isPrimitive()) {
++ return 'L';
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(parameterType);
++ assert (memo != null);
++ return (char) (Character) memo[2];
++ }
++
++ public static Class<?> basicTypeFromChar(char c) {
++ if (c == 'L') {
++ return Object.class;
++ }
++// if (c == '[') {
++// return Object[].class;
++// }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get((Character)c);
++ if (memo == null)
++ return null; // random junk character
++ return (Class<?>) memo[1];
++ }
++
++ public static Object zeroValue(Class<?> parameterType) {
++ if (!parameterType.isPrimitive()) {
++ return null;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(parameterType);
++ assert (memo != null);
++ return memo[3];
++ }
++
++ private static final HashMap<Object, Object[]> wrappers
++ = new HashMap<Object, Object[]>(20);
++
++ private static void fillWrappers() {
++ Object[][] memos = {
++ {Boolean.class, Boolean.TYPE, 'Z', (Boolean) false},
++ {Character.class, Character.TYPE, 'C', (Character) '\000'},
++ {Byte.class, Byte.TYPE, 'B', (Byte) (byte) 0},
++ {Short.class, Short.TYPE, 'S', (Short) (short) 0},
++ {Integer.class, Integer.TYPE, 'I', (Integer) 0},
++ {Long.class, Long.TYPE, 'J', (Long) 0L},
++ {Float.class, Float.TYPE, 'F', (Float) 0.0F},
++ {Double.class, Double.TYPE, 'D', (Double) 0.0},
++ {Void.class, Void.TYPE, 'V', null}
++ };
++ for (Object[] memo : memos) {
++ wrappers.put(memo[0], memo);
++ wrappers.put(memo[1], memo);
++ wrappers.put(memo[2], memo);
++ }
++ }
++}
+diff --git a/src/share/classes/java/dyn/WrongMethodTypeException.java b/src/share/classes/java/dyn/WrongMethodTypeException.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/WrongMethodTypeException.java
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 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
++ * 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 jrose
++ */
++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);
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/AMH.java b/src/share/classes/java/dyn/impl/AMH.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/AMH.java
+@@ -0,0 +1,45 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.*;
++import java.lang.reflect.Method;
++
++/**
++ * This method handle performs argument adaptation.
++ * @author jrose
++ */
++public class AMH extends MethodHandle {
++ final MH target;
++ Object[] values;
++ AMH(Method m, MH target, Object[] values) {
++ super(Access.TOKEN, MethodType.make(m));
++ this.target = target;
++ this.values = values;
++ MH.init(this);
++ checkHandler();
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/Access.java b/src/share/classes/java/dyn/impl/Access.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/Access.java
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.MethodHandles;
++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.
++ */
++ static private final String[] FRIENDS = {
++ "java.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 (callc.getClassLoader() == Access.class.getClassLoader()) {
++ String callcName = callc.getName();
++ for (String friend : FRIENDS) {
++ if (callcName.startsWith(friend))
++ return TOKEN;
++ }
++ }
++ throw new IllegalAccessError("bad caller: " + callc);
++ }
++
++ /**
++ * 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() {
++ Class<?> callc = Reflection.getCallerClass(3);
++ throw new IllegalAccessError("bad caller: " + callc);
++ }
++
++ static {
++ //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/BMH.java b/src/share/classes/java/dyn/impl/BMH.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/BMH.java
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.*;
++import java.util.Arrays;
++
++/**
++ * The flavor of method handle which emulates an invoke instruction
++ * on a predetermined receiver. The JVM dispatches to the correct method
++ * when the handle is created, not when it is invoked.
++ * @author jrose
++ */
++public class BMH extends MethodHandle {
++ final Object receiver;
++ BMH(DMH mh, Object receiver) {
++ super(Access.TOKEN, computeType(mh.type(), receiver));
++ this.receiver = receiver;
++ MH.init(this, mh, receiver);
++ checkHandler();
++ }
++
++ /** Make sure the receiver matches the first argument of the
++ * method type, and return the type without that argument.
++ */
++ static MethodType computeType(MethodType type, Object receiver) {
++ Class<?>[] ptypes = type.parameterArray();
++ Class<?> ptype0 = ptypes[0];
++ ptype0.cast(receiver); // check the type now (one last time)
++ ptypes = Arrays.copyOfRange(ptypes, 1, ptypes.length);
++ return MethodType.make(type.returnType(), ptypes);
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/DMH.java b/src/share/classes/java/dyn/impl/DMH.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/DMH.java
+@@ -0,0 +1,45 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.*;
++import java.lang.reflect.Method;
++import java.lang.reflect.Modifier;
++
++/**
++ * The flavor of method handle which emulates any of the invoke instructions.
++ * @author jrose
++ */
++class DMH extends MethodHandle {
++ DMH(MethodType mt, Method m, boolean doDispatch) {
++ super(Access.TOKEN, mt);
++ assert(doDispatch || !Modifier.isAbstract(m.getModifiers()));
++ if (MH.JVM_SUPPORT) {
++ MH.init(this, m, doDispatch);
++ checkHandler();
++ }
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/MH.java b/src/share/classes/java/dyn/impl/MH.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/MH.java
+@@ -0,0 +1,185 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.*;
++import java.lang.reflect.Field;
++import java.lang.reflect.Method;
++import java.lang.reflect.Modifier;
++
++/**
++ * Base class for method handles which are known to the Hotspot JVM.
++ * @author jrose
++ */
++public abstract class MH {
++
++ // This field may be used by the JVM. Do not change.
++ protected final MethodType type;
++
++ // Fields used only by the JVM. Do not use or change.
++ Object vmref; // often the method, could be something else
++ long vmdata; // additional data; could be an int or a C pointer
++ long entry; // call entry; a stub or method entry point
++
++ /**
++ * VM-based method handles must have a security token.
++ */
++ public MH(Access token, MethodType type) {
++ this.type = type;
++ Access.check(token);
++ }
++
++ /// Factory methods to create method handles:
++
++ /** Look up a given method.
++ * Callable only from MethodHandles.
++ * @param token Proof that the caller has access to this package.
++ * @param defc Declaring class of the desired method.
++ * @param name Name of the desired method.
++ * @param rcvc Receiver type of desired non-static method (else null)
++ * @param type Type of desired method (sans receiver)
++ * @param doDispatch Will MH perform virtual or interface dispatch?
++ * @param caller If not null, access-check relative to this class
++ * @return a DMH to the given method, or null if it does not exist
++ */
++ public static
++ MethodHandle findMethod(Access token,
++ Class<?> defc, String name,
++ Class<?> rcvc, MethodType type,
++ boolean doDispatch, Class<?> caller) {
++ // FIXME: check permissions of 'caller'
++ Access.check(token);
++ Method m = null;
++ try {
++ m = defc.getMethod(name, type.parameterArray());
++ } catch (NoSuchMethodException ex) {
++ return null;
++ } catch (SecurityException ex) {
++ return null;
++ }
++ boolean mStatic = Modifier.isStatic(m.getModifiers());
++ boolean hStatic = (rcvc == null);
++ if (mStatic != hStatic)
++ return null; // wrong kind of method
++ MethodType mtype = MethodType.make(m);
++ if (rcvc != null) {
++ // adjust the advertised receiver type to be exactly the one requested
++ if (!mtype.parameterType(0).isAssignableFrom(rcvc))
++ throw new IllegalArgumentException("incompatible receiver: "+rcvc);
++ mtype = mtype.newParameterType(0, rcvc);
++ }
++ return new DMH(mtype, m, doDispatch);
++ }
++
++ /** Unreflect a given method.
++ * Callable only from MethodHandles.
++ * @param token Proof that the caller has access to this package.
++ * @param m Method to unreflect.
++ * @param doDispatch Will MH perform virtual or interface dispatch?
++ * @param caller If not null, access-check relative to this class
++ * @return a DMH to the given method, or null if it does not exist
++ */
++ public static
++ MethodHandle findMethod(Access token,
++ Method m, boolean doDispatch,
++ Class<?> caller) {
++ // FIXME: check permissions of 'caller'
++ MethodType mtype = MethodType.make(m);
++ return new DMH(mtype, m, doDispatch);
++ }
++
++ public static
++ MethodHandle findField(Access TOKEN,
++ Field f, boolean isSetter,
++ Class<?> caller) {
++ // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
++ 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 mh Any direct method handle.
++ * @param receiver Receiver (or first static method argument) to pre-bind.
++ * @return a BMH for the given DMH, or null if it does not exist
++ */
++ public static
++ MethodHandle bindReceiver(Access TOKEN,
++ MethodHandle mh, Object receiver) {
++ if (mh instanceof DMH)
++ return new BMH((DMH)mh, receiver);
++ return null; // let caller try something else
++ }
++
++ protected void checkHandler() {
++ // every MH must have a entry; every constructor must call this check routine
++ if (entry == 0) noHandler();
++ }
++
++ // out-of-line error processing (never called, we hope):
++ private void noHandler() {
++ throw new NullPointerException();
++ }
++
++ @Override
++ public String toString() {
++ String name = JVM_SUPPORT ? methodName(this) : null;
++ if (name == null) name = "*";
++ return name + ":" + ((MethodHandle)this).type();
++ }
++
++ /// The JVM interface for this package is all here:
++
++ /** Initialize the method handle to adapt the call. */
++ static native void init(AMH self);
++ /** Initialize the method handle to call the correct method, directly. */
++ static native void init(BMH self, Object refm, Object receiver);
++ /** Initialize the method handle to call as if by invoke. */
++ static native void init(DMH self, Object refm, boolean doDispatch);
++
++ /** Initialize the method handle form to participate in JVM calls.
++ * This is done once per erased type.
++ */
++ static native void init(MTForm self, MethodType erased);
++
++ /** For debugging. Fetch the name of the handled method, if available. */
++ static native String methodName(MH self);
++
++ private static native void registerNatives();
++ static final boolean JVM_SUPPORT;
++ static {
++ boolean JVM_SUPPORT_;
++ try {
++ registerNatives();
++ JVM_SUPPORT_ = true;
++ } catch (UnsatisfiedLinkError ee) {
++ // ignore; if we use init() methods later we'll see linkage errors
++ JVM_SUPPORT_ = false;
++ }
++ JVM_SUPPORT = JVM_SUPPORT_;
++ //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "init");
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/MTForm.java b/src/share/classes/java/dyn/impl/MTForm.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/MTForm.java
+@@ -0,0 +1,52 @@
++/*
++ * Copyright 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
++ * 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.impl;
++
++import java.dyn.*;
++
++/**
++ * Base class for method types, which is known to the Hotspot JVM.
++ * @author jrose
++ */
++public abstract class MTForm {
++ // These fields may be used by the JVM. Do not change.
++ Object vmref;
++ long vmdata;
++
++ /**
++ * VM-based method handles must have a security token.
++ */
++ protected MTForm(Access token) {
++ Access.check(token);
++ }
++
++ protected void init(MethodType erased, int paramSlotCount) {
++ // send a few bits down to the JVM:
++ vmdata = paramSlotCount;
++
++ if (MH.JVM_SUPPORT) MH.init(this, erased);
++ }
++}
+diff --git a/src/share/classes/java/dyn/impl/package-info.java b/src/share/classes/java/dyn/impl/package-info.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/impl/package-info.java
+@@ -0,0 +1,35 @@
++/*
++ * Copyright 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
++ * 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.
++ */
++
++/**
++ * Implementation details for JSR 292 RI, package java.dyn.
++ * This particular version is specific to Hotspot.
++ * There is also a backport version of this sub-package which uses reflection,
++ * and can therefore run (slowly) on older versions of Java.
++ * Other JVM vendors may create their own versions of this sub-package.
++ * @author jrose
++ */
++
++package java.dyn.impl;
+diff --git a/src/share/classes/java/dyn/util/MethodHandleInvoker.java b/src/share/classes/java/dyn/util/MethodHandleInvoker.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/util/MethodHandleInvoker.java
+@@ -0,0 +1,317 @@
++/*
++ * Copyright 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
++ * under the terms make 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 make 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 make 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.util;
++
++import java.dyn.AnonymousClassLoader;
++import java.dyn.ConstantPoolParser;
++import java.dyn.ConstantPoolPatch;
++import java.dyn.ConstantPoolVisitor;
++import java.dyn.InvalidConstantPoolFormatException;
++import java.dyn.MethodHandle;
++import java.dyn.MethodType;
++import java.dyn.Wrappers;
++import java.dyn.WrongMethodTypeException;
++import java.io.IOException;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++import java.util.IdentityHashMap;
++
++/**
++ * Emulation make method handle invocation.
++ * Not needed if the JVM supports method handles natively.
++ * @author jrose
++ */
++public abstract
++class MethodHandleInvoker {
++ protected final MethodType type;
++
++ public MethodType type() { return type; }
++
++ protected MethodHandleInvoker(MethodType type) {
++ this.type = type;
++ }
++
++ // Type-specific entry points. Only one is defined at a time.
++ // The set make cases is motivated by the need for fast paths.
++ // Arity 0-1: [LJD](), [LJD]([LJD]),
++ // Arity 2-3, with prims:
++ // All others: L(LL), L(LLL), L(LLLL), L(LLLLLL...).
++ public void invoke_V(MethodHandle mh)
++ { throw wrongType(mh); }
++ public Object invoke_L(MethodHandle mh)
++ { throw wrongType(mh); }
++ public long invoke_J(MethodHandle mh)
++ { throw wrongType(mh); }
++ public double invoke_D(MethodHandle mh)
++ { throw wrongType(mh); }
++ public Object invoke_LL(MethodHandle mh, Object a0)
++ { throw wrongType(mh); }
++ public Object invoke_LLL(MethodHandle mh, Object a0, Object a1)
++ { throw wrongType(mh); }
++ public Object invoke_LLI(MethodHandle mh, Object a0, int a1)
++ { throw wrongType(mh); }
++
++ private static abstract class FakeMethodHandle extends MethodHandle {
++ public FakeMethodHandle() { super(null, null); }
++ // here are all the invokes we need to link against:
++ public abstract void fake_invoke_V();
++ public abstract Object fake_invoke_L();
++ public abstract long fake_invoke_J();
++ public abstract double fake_invoke_D();
++ public abstract Object fake_invoke_LL(Object a0);
++ public abstract Object fake_invoke_LLL(Object a0, Object a1);
++ public abstract Object fake_invoke_LLI(Object a0, int a1);
++ }
++
++ static class V extends MethodHandleInvoker {
++ static final int FINGERPRINT = fV;
++ public V(MethodType type) { super(type); }
++ @Override public void invoke_V(MethodHandle mh) {
++ checkType(mh);
++ ((FakeMethodHandle)mh).fake_invoke_V();
++ }
++ }
++
++ static class L extends MethodHandleInvoker {
++ static final int FINGERPRINT = fL;
++ public L(MethodType type) { super(type); }
++ @Override public Object invoke_L(MethodHandle mh) {
++ checkType(mh);
++ return ((FakeMethodHandle)mh).fake_invoke_L();
++ }
++ }
++
++ static class LL extends MethodHandleInvoker {
++ static final int FINGERPRINT = fL | fL<<fA0;
++ public LL(MethodType type) { super(type); }
++ @Override public Object invoke_LL(MethodHandle mh, Object a0) {
++ checkType(mh);
++ return ((FakeMethodHandle)mh).fake_invoke_LL(a0);
++ }
++ }
++
++ static class LLL extends MethodHandleInvoker {
++ static final int FINGERPRINT = fL | fL<<fA0 | fL<<fA1;
++ public LLL(MethodType type) { super(type); }
++ @Override public Object invoke_LLL(MethodHandle mh, Object a0, Object a1) {
++ checkType(mh);
++ return ((FakeMethodHandle)mh).fake_invoke_LLL(a0, a1);
++ }
++ }
++
++ static class LLI extends MethodHandleInvoker {
++ static final int FINGERPRINT = fL | fL<<fA0 | fI<<fA1;
++ public LLI(MethodType type) { super(type); }
++ @Override public Object invoke_LLI(MethodHandle mh, Object a0, int a1) {
++ checkType(mh);
++ return ((FakeMethodHandle)mh).fake_invoke_LLI(a0, a1);
++ }
++ }
++
++ public static MethodHandleInvoker make(MethodType type) {
++ MethodHandleInvoker inv = null;
++ synchronized (invokers) {
++ inv = invokers.get(type);
++ }
++ if (inv != null) return inv;
++ Class<? extends MethodHandleInvoker> template = null;
++ Class<? extends MethodHandleInvoker> instance = null;
++ Constructor<? extends MethodHandleInvoker> constr = null;
++ int fprt = fingerprint(type);
++ switch (fprt) {
++ case V.FINGERPRINT: template = V.class; break;
++ case L.FINGERPRINT: template = L.class; break;
++ case LL.FINGERPRINT: template = LL.class; break;
++ case LLL.FINGERPRINT: template = LLL.class; break;
++ case LLI.FINGERPRINT: template = LLI.class; break;
++ }
++ if (template == null) {
++ throw new UnsupportedOperationException(
++ "NYI: No template for "+type+", fp="+Integer.toHexString(fprt));
++ } else {
++ try {
++ instance = expandTemplate(template, fprt, type);
++ constr = instance.getConstructor(MethodType.class);
++ inv = constr.newInstance(type);
++ } catch (IOException ex) {
++ printex(ex);
++ } catch (InvalidConstantPoolFormatException ex) {
++ printex(ex);
++ } catch (InstantiationException ex) {
++ printex(ex);
++ } catch (IllegalAccessException ex) {
++ printex(ex);
++ } catch (NoSuchMethodException ex) {
++ printex(ex);
++ } catch (IllegalArgumentException ex) {
++ printex(ex);
++ } catch (InvocationTargetException ex) {
++ printex(ex);
++ }
++ }
++ if (inv == null) {
++ // %%% FIXME: assemble missing classes on the fly,
++ // or maybe get the JVM to help
++ throw new UnsupportedOperationException("NYI");
++ }
++ synchronized (invokers) {
++ MethodHandleInvoker inv2 = invokers.get(type);
++ if (inv2 == null)
++ invokers.put(type, inv);
++ else
++ inv = inv2;
++ }
++ return inv;
++ }
++
++ private static final AnonymousClassLoader LOADER
++ = new AnonymousClassLoader(MethodHandleInvoker.class);
++
++ private static void printex(Exception ex) {
++ System.out.println("*** Unexpected exception in "+MethodHandleInvoker.class);
++ System.out.println(ex);
++ ex.printStackTrace(System.out);
++ }
++ private static String utf8Name(Class<?> cls) {
++ return cls.getName().replace('.', '/');
++ }
++
++ private static class TemplateExpander extends ConstantPoolVisitor {
++ ConstantPoolParser cp;
++ ConstantPoolPatch patch;
++
++ // Pairs make strings to be rewritten:
++ String fakeMHName = utf8Name(FakeMethodHandle.class);
++ String realMHName = utf8Name(MethodHandle.class);
++ boolean didMHName;
++
++ String fakeInvokeName, realInvokeName = "invoke";
++ String fakeInvokeSig, realInvokeSig;
++ boolean didInvokeName, didInvokeSig;
++
++ @Override
++ public void visitUTF8(int index, byte tag, String utf8) {
++ String orig = utf8;
++ if (utf8.equals(fakeMHName)) {
++ utf8 = realMHName; didMHName = true;
++ }
++ if (utf8.equals(fakeInvokeName)) {
++ utf8 = realInvokeName; didInvokeName = true;
++ }
++ if (utf8.equals(fakeInvokeSig)) {
++ utf8 = realInvokeSig; didInvokeSig = true;
++ }
++ if ((Object)utf8 != orig)
++ patch.putUTF8(index, utf8);
++ }
++
++ public TemplateExpander(Class<? extends MethodHandleInvoker> template,
++ int fprt, MethodType realMType)
++ throws IOException, InvalidConstantPoolFormatException {
++ Object[] desc = fingerprintInvokeDescriptor(fprt);
++ MethodType fakeInvokeMType = (MethodType) desc[1];
++ if (realMType.erase() != fakeInvokeMType)
++ // this will fail for various corner cases we need to figure out later
++ throw new RuntimeException("what?? "+realMType+" !eraseTo "+fakeInvokeMType);
++ fakeInvokeSig = fakeInvokeMType.toBytecodeString();
++ realInvokeSig = realMType.toBytecodeString();
++ fakeInvokeName = "fake_"+desc[0];
++ cp = new ConstantPoolParser(template);
++ patch = cp.createPatch();
++ cp.parse(this);
++ if (!(didMHName && didInvokeName && didInvokeSig))
++ throw new RuntimeException("utf8 rewrites failed");
++ }
++ }
++
++ static final IdentityHashMap<MethodType,MethodHandleInvoker> invokers
++ = new IdentityHashMap<MethodType, MethodHandleInvoker>();
++
++ private static Class<? extends MethodHandleInvoker>
++ expandTemplate(Class<? extends MethodHandleInvoker> template,
++ int fprt, MethodType type)
++ throws IOException, InvalidConstantPoolFormatException {
++ TemplateExpander tex = new TemplateExpander(template, fprt, type);
++ return LOADER.loadClass(tex.patch).asSubclass(MethodHandleInvoker.class);
++ }
++
++ // fingerprint components and positional scale factors
++ static final int fV = 0, fL = 1, fI = 2, fJ = 3, fF = 4, fD = 5;
++ static final String FP_SIGCHARS = "VLIJFD";
++ static final int fRw = 4, fAw = 3; // bit-width make return and arg slices
++ static final int fA0 = fRw, fA1 = fA0+fAw, fA2 = fA1+fAw, fA3 = fA2+fAw;
++ static final int fA_MAX = (32-fRw)/fAw, fR_MASK = (1<<fRw)-1, fA_MASK = (1<<fAw)-1;
++
++ static int fingerprint(MethodType type) {
++ int np = type.parameterCount();
++ if (np > fA_MAX) return -1;
++ int fprt = fingerprint(type.returnType());
++ int shift = fRw;
++ for (int i = 0; i < np; i++) {
++ fprt |= fingerprint(type.parameterType(i)) << shift;
++ shift += fAw;
++ }
++ assert(shift <= 32);
++ return fprt;
++ }
++
++ static int fingerprint(Class<?> type) {
++ char ch = Wrappers.basicTypeChar(type);
++ int i = FP_SIGCHARS.indexOf(ch);
++ assert(i >= 0 || "ZCBS".indexOf(ch) >= 0);
++ return (i >= 0) ? i : fI;
++ }
++
++ static String fingerprintName(int fprt) {
++ assert(fprt != -1);
++ StringBuilder sb = new StringBuilder();
++ sb.append(FP_SIGCHARS.charAt(fprt & fA_MASK));
++ for (fprt >>>= fRw; fprt != 0; fprt >>>= fAw)
++ sb.append(FP_SIGCHARS.charAt(fprt & fA_MASK));
++ return sb.toString();
++ }
++
++ static Object[] fingerprintInvokeDescriptor(int fprt) {
++ String fpName = fingerprintName(fprt);
++ Class<?>[] ptypes = new Class<?>[fpName.length()-1];
++ Class<?> rtype = Wrappers.basicTypeFromChar(fpName.charAt(0));
++ for (int i = 0; i < ptypes.length; i++)
++ ptypes[i] = Wrappers.basicTypeFromChar(fpName.charAt(i+1));
++ String invokeName = "invoke_"+fpName;
++ MethodType invokeType = MethodType.make(rtype, ptypes);
++ return new Object[]{ invokeName, invokeType };
++ }
++
++ /** Throw this if a bad entry point is taken. */
++ protected RuntimeException wrongType(MethodHandle mh) {
++ return new WrongMethodTypeException("wrong call type for "+mh+
++ " should be "+type+" in "+this);
++ }
++ protected void checkType(MethodHandle mh) {
++ if (mh.type() != type)
++ throw wrongType(mh);
++ }
++}
+diff --git a/src/share/classes/java/dyn/util/RewriteFakeMethodHandles.java b/src/share/classes/java/dyn/util/RewriteFakeMethodHandles.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/util/RewriteFakeMethodHandles.java
+@@ -0,0 +1,200 @@
++/*
++ * Copyright 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
++ * 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.util;
++
++import java.dyn.*;
++import java.io.BufferedInputStream;
++import java.io.ByteArrayInputStream;
++import java.io.ByteArrayOutputStream;
++import java.io.File;
++import java.io.FileInputStream;
++import java.io.FileOutputStream;
++import java.io.IOException;
++import java.io.InputStream;
++import java.io.OutputStream;
++import java.nio.charset.Charset;
++
++/**
++ * Replace classes named "*FakeMethodHandle" with true MethodHandle references.
++ */
++class RewriteFakeMethodHandles {
++ final static boolean TESTING = false;
++ public static void main(String... av) throws Exception {
++ if (TESTING && av.length == 0)
++ av = new String[] { "build/classes" };
++ if (av.length == 0)
++ throw new RuntimeException("Usage: FoldMethodHandleReferences file...");
++ int nf = 0;
++ for (String arg : av) {
++ nf += fold(new File(arg));
++ }
++ System.out.println("Changed "+nf+" files.");
++ }
++ public static int fold(File f) throws IOException {
++ int nf = 0;
++ if (f.isDirectory()) {
++ // Process every class file in the directory hierarchy.
++ // But avoid class files for the fake method handle types.
++ for (File sf : f.listFiles()) {
++ if ((sf.getName().endsWith(".class")
++ && !sf.getName().endsWith(mhSuffixDotClass))
++ || sf.isDirectory())
++ nf += fold(sf);
++ }
++ return nf;
++ }
++
++ if (TESTING) System.out.println("fold "+f);
++
++ // now hex-edit the bytecodes
++ InputStream is = new FileInputStream(f);
++ ByteArrayOutputStream os = new ByteArrayOutputStream(is.available());
++ is = new BufferedInputStream(is);
++ try {
++ boolean changed = fold(is, os);
++ if (changed) nf++;
++ } finally {
++ is.close();
++ }
++ File tmpf = File.createTempFile("cls", "dat", f.getParentFile());
++ OutputStream fos = new FileOutputStream(tmpf);
++ try {
++ fos.write(os.toByteArray());
++ } finally {
++ fos.close();
++ }
++ if (!tmpf.renameTo(f))
++ throw new IOException("rename failed on "+f);
++ return nf;
++ }
++
++ public static byte[] fold(byte[] in) {
++ return fold(in, 0, in.length);
++ }
++ public static byte[] fold(byte[] bytes, int offset, int length) {
++ ByteArrayOutputStream out = new ByteArrayOutputStream();
++ ByteArrayInputStream in = new ByteArrayInputStream(bytes, offset, length);
++ try {
++ boolean changed = fold(in, out);
++ if (!changed && offset == 0 && length == bytes.length)
++ return bytes;
++ } catch (IOException ex) {
++ throw new InternalError(ex.toString());
++ }
++ return out.toByteArray();
++ }
++ public static boolean fold(InputStream is, OutputStream os) throws IOException {
++ ByteArrayOutputStream buf = new ByteArrayOutputStream();
++ // header of class file:
++ // magic: u4; majmin: u4; cplen: u2; cpentry[cplen]; ...
++ boolean bad = false;
++ boolean changed = false;
++ int magic = (copyU2(is, os) << 16) | copyU2(is, os);
++ if (magic != 0xCAFEBABE)
++ bad = true;
++ if ((copyU2(is, os) | copyU2(is, os)) < 0) // maj, min
++ bad = true;
++ int cplen = bad ? -1 : copyU2(is, os);
++ if (cplen <= 0)
++ bad = true;
++ for (int i = 1; i < cplen; i++) {
++ int tag = copyU1(is, os);
++ int ok;
++ if (tag == 1) {
++ int utf8len = copyU2(is, buf);
++ buf.reset();
++ ok = copyN(utf8len, is, buf);
++ if (ok >= 0) {
++ byte[] str = buf.toByteArray();
++ byte[] fstr = foldName(str);
++ os.write(fstr.length >> 8);
++ os.write(fstr.length >> 0);
++ os.write(fstr);
++ if (fstr != str)
++ changed = true;
++ }
++ } else {
++ int len = (tag >= 0 && tag < cpSize.length) ? cpSize[tag] : 0;
++ if (len > 0) {
++ ok = copyN(len, is, os);
++ } else {
++ ok = -1;
++ }
++ }
++ if (ok < 0) { bad = true; break; }
++ }
++ if (bad)
++ throw new IOException("bad class file format");
++ for (int ch; (ch = is.read()) >= 0; ) {
++ os.write(ch);
++ }
++ return changed;
++ }
++
++ private static int copyU1(InputStream is, OutputStream os)
++ throws IOException {
++ int ch = is.read();
++ if (ch >= 0) os.write(ch);
++ return ch;
++ }
++ private static int copyU2(InputStream is, OutputStream os) throws IOException {
++ return (copyU1(is, os) << 8) | copyU1(is, os);
++ }
++ private static int copyN(int n, InputStream is, OutputStream os) throws IOException {
++ for (int i = 0; i < n; i++) {
++ int ch = copyU1(is, os);
++ if (ch < 0) return ch;
++ }
++ return n;
++ }
++
++ static private final int[] cpSize = {
++ 0, -1, 0, 4, 4, 8, 8, 2, 2, 4, 4, 4, 4
++ };
++ static private final String mhSuffixS = "FakeMethodHandle";
++ static private final String mhSuffixDotClass = mhSuffixS+".class";
++ static private final String mhNameS = MethodHandle.class.getName().replace('.', '/');
++ // byte array versions of the key strings:
++ static private Charset utf8CS = Charset.forName("UTF8");
++ static private final byte[] mhSuffixA = mhSuffixS.getBytes(utf8CS);
++ static private final byte[] mhNameA = mhNameS.getBytes(utf8CS);
++ public static String foldName(String s) {
++ if (s.endsWith(mhSuffixS))
++ return mhNameS;
++ return s;
++ }
++ public static byte[] foldName(byte[] ba) {
++ int baStart = ba.length - mhSuffixA.length;
++ if (baStart <= 0) return ba;
++ for (int i = 0; i < mhSuffixA.length; i++)
++ if (mhSuffixA[i] != ba[baStart + i])
++ return ba;
++ if (TESTING) System.out.println("fold name "+new String(ba));
++ // if it is a match, throw away the whole string,
++ // and replace by java/dyn/MethodHandle
++ return mhNameA;
++ }
++}
+diff --git a/src/share/classes/java/dyn/util/package-info.java b/src/share/classes/java/dyn/util/package-info.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/util/package-info.java
+@@ -0,0 +1,31 @@
++/*
++ * Copyright 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
++ * 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.
++ */
++
++/**
++ * Extra support for using JSR 292 RI, package java.dyn.
++ * @author jrose
++ */
++
++package java.dyn.util;