Refresh hotspot to build 42
authorjrose
Wed Dec 24 20:17:36 2008 -0800 (11 months ago)
changeset 121ba2ea4e1a1a
parent 1114ece316ef24
child 13bab113128656
Refresh hotspot to build 42
meth.patch
--- a/meth.patch Wed Nov 12 22:24:27 2008 -0800
+++ b/meth.patch Wed Dec 24 20:17:36 2008 -0800
@@ -1,140 +1,8 @@ diff --git a/src/share/classes/java/dyn/
-diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java
+diff --git a/src/share/classes/impl/java/dyn/Access.java b/src/share/classes/impl/java/dyn/Access.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 @@
++++ b/src/share/classes/impl/java/dyn/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.
@@ -160,15 +28,2474 @@ new file mode 100644
+ * have any questions.
+ */
+
++package impl.java.dyn;
++
++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/impl/java/dyn/AdapterMethodHandle.java b/src/share/classes/impl/java/dyn/AdapterMethodHandle.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/AdapterMethodHandle.java
+@@ -0,0 +1,427 @@
++/*
++ * 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 impl.java.dyn;
++
++import impl.java.dyn.util.Wrappers;
++import java.dyn.*;
++import java.util.ArrayList;
++import java.util.List;
++
++/**
++ * This method handle performs simple conversion or checking of a single argument.
++ * @author jrose
++ */
++public class AdapterMethodHandle extends BoundMethodHandle {
++ //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
++ //Object argument; // parameter to the conversion if needed
++ //int vmargslot; // which argument slot is affected
++ private final int conversion; // the type of conversion: RETYPE_ONLY, etc.
++
++ // Constructors in this class *must* be package scoped or private.
++ private AdapterMethodHandle(MethodHandle target, MethodType newType,
++ long conv, Object convArg) {
++ super(newType, convArg, newType.parameterSlot(convArgPos(conv)));
++ this.conversion = convCode(conv);
++ if (MethodHandle.JVM_SUPPORT) {
++ // JVM might update VM-specific bits of conversion (ignore)
++ MethodHandleImpl.init(this, target, convArgPos(conv));
++ }
++ }
++ private AdapterMethodHandle(MethodHandle target, MethodType newType,
++ long conv) {
++ this(target, newType, conv, null);
++ }
++
++ // TO DO: When adapting a DMH, use direct retyping if possible
++
++ /** Create a JVM-level adapter which will call the target MethodHandleImpl after
++ * possibly narrowing, casting, or dropping arguments.
++ * @param target the target to invoke after arguments are adjusted
++ * @param adapterType the method type of the desired result
++ * @param dropArguments args to drop; &gt;0 means final, &lt;0 means initial
++ * @return an AdapterMethodHandle which does the job
++ * @throws WrongMethodTypeException if the conversions are too complex
++ */
++ static MethodHandle makePrimCast(MethodHandle target,
++ MethodType newType,
++ int dropArguments) {
++ MethodType oldType = target.type();
++ if (oldType == newType && dropArguments == 0)
++ return target; // well, that was easy
++
++ // Check return type. (Not much can be done with it.)
++ Class<?> src = oldType.returnType();
++ Class<?> dest = newType.returnType();
++ int pass = MethodHandleImpl.canPassUnchecked(src, dest);
++ if (pass <= 0)
++ throw new WrongMethodTypeException(newType+": cannot return unchecked value from "+target);
++
++ MethodType midType;
++ int nargs = newType.parameterCount();
++ MethodType dropConvType = null;
++
++ int dropArgCount = nargs - oldType.parameterCount();
++ int dropArgPos = -1;
++ if (dropArgCount != 0) {
++ if (dropArgCount < 0)
++ throw new WrongMethodTypeException(newType+": not enough arguments for target "+target);
++ List<Class<?>> argList = newType.parameterList();
++ if (dropArguments == -dropArgCount) {
++ // It's OK for the target to ignore some arguments.
++ // Because of the way the JVM stack grows, an adapter can
++ // trivially ignore an initial sequence of arguments.
++ // (Actually, the JVM extends some work closing up the
++ // unused space on the stack.)
++ argList = argList.subList(dropArgCount, argList.size());
++ dropArgPos = 0;
++ } else if (dropArguments == dropArgCount) {
++ // Create a stack-cutter adapter now, to remove trailing args.
++ argList = argList.subList(0, argList.size()-dropArgCount);
++ dropArgPos = oldType.parameterCount();
++ } else {
++ throw new WrongMethodTypeException(newType+": cannot drop #"+dropArguments+" to match "+target);
++ }
++ midType = MethodType.make(newType.returnType(), argList);
++ dropArgCount = midType.parameterSlotCount()
++ - newType.parameterSlotCount();
++ assert(dropArgCount >= dropArgCount);
++ assert(dropArgCount <= dropArgCount + (newType.parameterSlotCount() - newType.parameterCount()));
++ newType = midType;
++ nargs = newType.parameterCount();
++ }
++ assert(nargs == oldType.parameterCount());
++
++ // work backwards through the argument pairs...
++ int sawLongs = 0;
++ for (int i = nargs; --i >= 0; ) {
++ src = newType.parameterType(i);
++ dest = oldType.parameterType(i);
++ pass = MethodHandleImpl.canPassUnchecked(src, dest);
++ if (pass == 0)
++ throw new WrongMethodTypeException(newType+": cannot convert arg #"+i+" for target "+target);
++ if (pass > 0) continue;
++ // need a conversion at this point
++ if (!dest.isPrimitive() && !src.isPrimitive()) {
++ midType = oldType.changeParameterType(i, src);
++ target = makeCheckCast(midType, i, dest, target);
++ oldType = midType;
++ } else if (canPrimCast(basicType(src), basicType(dest))) {
++ midType = oldType.changeParameterType(i, src);
++ target = makePrimCast(target, midType, i, basicType(src), basicType(dest));
++ oldType = midType;
++ }
++ }
++
++ // No more explicit conversions needed.
++ // Finish with a dropping and/or retyping AdapterMethodHandle.
++ if (dropArgCount != 0) {
++ newType = dropConvType;
++ target = makeDropArguments(newType, dropArgPos, dropArgCount, target);
++ }
++ if (target.type() == newType)
++ return target;
++ else
++ return makeRetypeOnly(newType, target);
++ }
++
++ /** Conversions recognized by the JVM.
++ * They must align with enum AdapterKind in vm/prims/methodHandles.hpp.
++ */
++ static final short
++ RETYPE_ONLY = 0x000, // no argument changes; straight retype
++ CHECK_CAST = 0x100, // ref-to-ref conversion; requires a Class argument
++ PRIM_TO_PRIM = 0x200, // converts from one primitive to another
++ REF_TO_PRIM = 0x300, // unboxes a wrapper to produce a primitive
++ PRIM_TO_REF = 0x400, // boxes a primitive into a wrapper (NYI)
++ SWAP_ARGS = 0x500, // permutes arguments (NYI)
++ DUP_ARGS = 0x600, // duplicates one or more arguments (at TOS)
++ DROP_ARGS = 0x700, // remove one or more argument slots
++ COLLECT_ARGS = 0x800, // combine one or more arguments into a varargs (NYI)
++ SPREAD_ARGS = 0x900, // expand in place a varargs array (of known size)
++ FLYBY = 0xA00, // operate first on reified argument list (NYI)
++ RICOCHET = 0xB00; // run an adapter chain on the return value (NYI)
++ static final int
++ CONV_OP_MASK = 0xF00, // byte 3 contains the conversion op field
++ CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
++ CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
++ CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
++ CONV_DEST_TYPE_SHIFT = 12, // byte 3 has the target BasicType (if needed)
++ CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
++ CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
++ CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
++
++ /** Basic types as encoded in the JVM. */
++ static final byte
++ T_BOOLEAN = 4,
++ T_CHAR = 5,
++ T_FLOAT = 6,
++ T_DOUBLE = 7,
++ T_BYTE = 8,
++ T_SHORT = 9,
++ T_INT = 10,
++ T_LONG = 11,
++ T_OBJECT = 12,
++ //T_ARRAY = 13
++ T_VOID = 14;
++ //T_ADDRESS = 15
++
++ static byte basicType(Class<?> type) {
++ if (type == null) return T_VOID;
++ char c = Wrappers.basicTypeChar(type);
++ switch (c) {
++ case 'Z': return T_BOOLEAN;
++ case 'C': return T_CHAR;
++ case 'F': return T_FLOAT;
++ case 'D': return T_DOUBLE;
++ case 'B': return T_BYTE;
++ case 'S': return T_SHORT;
++ case 'I': return T_INT;
++ case 'J': return T_LONG;
++ case 'L': return T_OBJECT;
++ }
++ return 99; // T_ILLEGAL or some such
++ }
++
++ /** Number of stack slots for the given type.
++ * Two for T_DOUBLE and T_FLOAT, one for the rest.
++ */
++ static int type2size(byte type) {
++ assert(type >= T_BOOLEAN && type <= T_OBJECT);
++ return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
++ }
++
++ /** Construct an adapter conversion descriptor for a single-argument conversion. */
++ static long makeConv(short convOp, int argnum, byte src, byte dest) {
++ assert(src == (src & 0xF));
++ assert(dest == (dest & 0xF));
++ assert(convOp == (convOp & CONV_OP_MASK));
++ assert(convOp >= CHECK_CAST && convOp <= PRIM_TO_REF);
++ long stackMove = type2size(dest) - type2size(src);
++ return ((long) argnum << 32 |
++ (long) convOp |
++ (int) src << CONV_SRC_TYPE_SHIFT |
++ (int) dest << CONV_DEST_TYPE_SHIFT |
++ stackMove << CONV_STACK_MOVE_SHIFT
++ );
++ }
++ static long makeConv(short convOp, int argnum, int stackMove) {
++ assert(convOp == (convOp & CONV_OP_MASK));
++ assert(convOp >= SWAP_ARGS && convOp <= SPREAD_ARGS);
++ byte src = 0, dest = 0;
++ if (convOp >= COLLECT_ARGS && convOp <= SPREAD_ARGS)
++ src = dest = T_OBJECT;
++ return ((long) argnum << 32 |
++ (long) convOp |
++ (int) src << CONV_SRC_TYPE_SHIFT |
++ (int) dest << CONV_DEST_TYPE_SHIFT |
++ stackMove << CONV_STACK_MOVE_SHIFT
++ );
++ }
++ static long makeConv(short convOp) {
++ assert(convOp == (convOp & CONV_OP_MASK));
++ assert(convOp == RETYPE_ONLY);
++ return (long) convOp; // stackMove, src, dest, argnum all zero
++ }
++ static int convCode(long conv) {
++ return (int)conv;
++ }
++ static int convArgPos(long conv) {
++ return (int)(conv >>> 32);
++ }
++
++ @Override
++ public String toString() {
++ MethodType adaptedType = ((MethodHandle)this).type();
++ Object namh = nonAdapter((MethodHandle)vmtarget);
++ if (namh == null) namh = "unknown";
++ return "Adapted[" + adaptedType + "," + namh + "]";
++ }
++
++ private static MethodHandle nonAdapter(MethodHandle mh) {
++ return (MethodHandle)
++ MethodHandleImpl.getTarget(mh, MethodHandleImpl.ETF_DIRECT_HANDLE);
++ }
++
++ /* Return one plus the position of the first non-trivial difference
++ * between the given types. This is not a symmetric operation;
++ * we are considering adapting the targetType to adapterType.
++ * Trivial differences are those which could be ignored by the JVM
++ * without subverting the verifier. Otherwise, adaptable differences
++ * are ones for which we could create an adapter to make the type change.
++ * Return zero if there are no differences (other than trivial ones).
++ * Return 1+N if N is the only adaptable argument difference.
++ * Return the -2-N where N is the first of several adaptable
++ * argument differences.
++ * Return -1 if there there are differences which are not adaptable.
++ */
++ private static int diffTypes(MethodType adapterType,
++ MethodType targetType) {
++ Class<?> src = targetType.returnType();
++ Class<?> dest = adapterType.returnType();
++ if (MethodHandleImpl.canPassUnchecked(src, dest) <= 0)
++ return -1;
++ int nargs = adapterType.parameterCount();
++ if (nargs != targetType.parameterCount())
++ return -1;
++ int diff = diffTypes(adapterType, 0, targetType, 0, nargs);
++ System.out.println("diff "+adapterType);
++ System.out.println(" "+diff+" "+targetType);
++ return diff;
++ }
++ private static int diffTypes(MethodType adapterType, int tstart,
++ MethodType targetType, int astart,
++ int nargs) {
++ int res = 0;
++ for (int i = 0; i < nargs; i++) {
++ Class<?> src = adapterType.parameterType(tstart+i);
++ Class<?> dest = targetType.parameterType(astart+i);
++ if (MethodHandleImpl.canPassUnchecked(src, dest) <= 0) {
++ // found a difference; is it the only one so far?
++ if (res != 0)
++ return -1-res; // return -2-i for prev. i
++ res = 1+i;
++ }
++ }
++ return res;
++ }
++
++ /** Can a retyping adapter (alone) validly convert target to newType? */
++ static boolean canRetypeOnly(MethodType newType, MethodHandle target) {
++ return diffTypes(newType, target.type()) == 0;
++ }
++
++ /** Factory method: Performs no conversions; simply retypes the target. */
++ static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
++ assert(canRetypeOnly(newType, target));
++ return new AdapterMethodHandle(target, newType, makeConv(RETYPE_ONLY));
++ }
++
++ /** Can an adapter simply drop arguments to convert target to newType? */
++ static boolean canDropArguments(MethodType newType,
++ int dropArgPos, int dropArgCount,
++ MethodHandle target) {
++ MethodType oldType = target.type();
++ List<Class<?>> ptypes = oldType.parameterList();
++ int nptypes = ptypes.size();
++ if ((dropArgPos | dropArgCount) < 0)
++ return false;
++ if (dropArgPos == 0)
++ ptypes = ptypes.subList(dropArgCount, nptypes);
++ else if (dropArgPos + dropArgCount == nptypes)
++ ptypes = ptypes.subList(0, nptypes - dropArgCount);
++ else {
++ if (dropArgPos > nptypes ||
++ dropArgPos + dropArgCount > nptypes)
++ return false;
++ ptypes = new ArrayList<Class<?>>(ptypes);
++ ptypes.subList(dropArgPos, dropArgPos + dropArgCount).clear();
++ }
++ MethodType midType = MethodType.make(oldType.returnType(), ptypes);
++ return diffTypes(newType, midType) == 0;
++ }
++
++ /** Factory method: Drop selected initial or final arguments. */
++ static MethodHandle makeDropArguments(MethodType newType,
++ int dropArgPos, int dropArgCount,
++ MethodHandle target) {
++ assert(canDropArguments(newType, dropArgPos, dropArgCount, target));
++ MethodType mt = target.type();
++ int argCount = mt.parameterCount();
++ int dropSlotCount, dropSlotPos;
++ if (dropArgCount <= 0) {
++ return makeRetypeOnly(newType, target);
++ } else if (dropArgCount >= argCount) {
++ assert(dropArgPos == argCount-1);
++ dropSlotPos = 0;
++ dropSlotCount = mt.parameterSlotCount();
++ } else {
++ // arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ]
++ int lastDroppedArg = dropArgPos + dropArgCount - 1;
++ int lastKeptArg = dropArgPos - 1; // might be -1, which is OK
++ dropSlotPos = mt.parameterSlot(lastDroppedArg);
++ int lastKeptSlot = mt.parameterSlot(lastKeptArg);
++ dropSlotCount = lastKeptSlot - dropSlotPos;
++ assert(dropSlotCount >= dropArgCount);
++ }
++ long conv = makeConv(DROP_ARGS, dropArgPos, +dropSlotCount);
++ return new AdapterMethodHandle(target, newType, dropSlotCount, conv);
++ }
++
++ /** Can a checkcast adapter validly convert target to newType? */
++ static boolean canCheckCast(MethodType newType,
++ int arg, Class<?> destClass,
++ MethodHandle target) {
++ if (destClass.isPrimitive()) return false; // must be ref cast
++ MethodType targetType = target.type();
++ int pass = MethodHandleImpl.canPassUnchecked(destClass, targetType.parameterType(arg));
++ if (pass <= 0)
++ return false;
++ pass = MethodHandleImpl.canPassUnchecked(newType.parameterType(arg), destClass);
++ if (pass >= 0)
++ return (pass != 0);
++ int diff = diffTypes(newType, target.type());
++ // allow any cast between reference types, even a silly one
++ return (diff == 0 || diff == arg+1);
++ }
++
++ /** Factory method: Forces a cast at the given argument. */
++ static MethodHandle makeCheckCast(MethodType newType,
++ int arg, Class<?> destClass,
++ MethodHandle target) {
++ assert(canCheckCast(newType, arg, destClass, target));
++ long conv = makeConv(CHECK_CAST, arg, T_OBJECT, T_OBJECT);
++ return new AdapterMethodHandle(target, newType, conv, destClass);
++ }
++
++ /** Can an primitive conversion adapter validly convert target to newType? */
++ static boolean canPrimCast(MethodType newType, int arg, MethodHandle target) {
++ if (arg >= newType.parameterCount())
++ return false;
++ MethodType oldType = target.type();
++ int diff = diffTypes(newType, oldType);
++ if (diff != 0 && diff != arg+1)
++ return false;
++ byte src = basicType(newType.parameterType(arg));
++ byte dest = basicType(oldType.parameterType(arg));
++ return canPrimCast(src, dest);
++ }
++ /** Can an primitive conversion adapter validly convert src to dest? */
++ static boolean canPrimCast(byte src, byte dest) {
++ if (src >= T_OBJECT || dest >= T_OBJECT)
++ return false;
++ if (src == T_FLOAT || dest == T_FLOAT)
++ return (src ^ dest) == (T_FLOAT ^ T_DOUBLE);
++ return true;
++ }
++
++ /** Factory method: Truncate the given argument with zero or sign extension. */
++ static MethodHandle makePrimCast(MethodHandle target, MethodType newType,
++ int arg, byte src, byte dest) {
++ assert(canPrimCast(newType, arg, target));
++ long conv = makeConv(PRIM_TO_PRIM, arg, src, dest);
++ return new AdapterMethodHandle(target, newType, conv);
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/BoundMethodHandle.java b/src/share/classes/impl/java/dyn/BoundMethodHandle.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/BoundMethodHandle.java
+@@ -0,0 +1,88 @@
++/*
++ * 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 impl.java.dyn;
++
++import java.dyn.*;
++
++/**
++ * The flavor of method handle which emulates an invoke instruction
++ * on a predetermined argument. The JVM dispatches to the correct method
++ * when the handle is created, not when it is invoked.
++ * @author jrose
++ */
++public class BoundMethodHandle extends MethodHandle {
++ //MethodHandle vmtarget; // next BMH or final DMH or methodOop
++ private final Object argument; // argument to insert
++ private final int vmargslot; // position at which it is inserted
++
++ // Constructors in this class *must* be package scoped or private.
++
++ /** Bind a direct MH to its receiver (or first ref. argument).
++ * The JVM will pre-dispatch the MH if it is not already static.
++ */
++ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
++ super(Access.TOKEN, mh.type().deleteParameterType(0));
++ // check the type now, once for all:
++ this.argument = mh.type().parameterType(0).cast(argument);
++ this.vmargslot = this.type().parameterSlotCount();
++ if (MethodHandle.JVM_SUPPORT) {
++ this.vmtarget = null; // maybe updated by JVM
++ MethodHandleImpl.init(this, mh, 0);
++ } else {
++ this.vmtarget = mh;
++ }
++ }
++
++ /** Insert an argument into an arbitrary method handle.
++ * If argnum is zero, inserts the first argument, etc.
++ */
++ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
++ super(Access.TOKEN, mh.type().deleteParameterType(argnum));
++ this.argument = mh.type().parameterType(argnum).cast(argument);
++ this.vmargslot = this.type().parameterSlot(argnum-1);
++ System.out.println("init BMH type="+type()+" argnum="+argnum+" vmargslot="+vmargslot);
++ if (MethodHandle.JVM_SUPPORT) {
++ this.vmtarget = null; // maybe updated by JVM
++ MethodHandleImpl.init(this, mh, argnum);
++ } else {
++ this.vmtarget = mh;
++ }
++ }
++
++ /** For subclasses only.
++ */
++ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
++ super(Access.TOKEN, type);
++ this.argument = argument;
++ this.vmargslot = vmargslot;
++ assert(this.getClass() != BoundMethodHandle.class);
++ }
++
++ @Override
++ public String toString() {
++ return "Bound[" + super.toString() + "]";
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/CallSiteImpl.java b/src/share/classes/impl/java/dyn/CallSiteImpl.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/CallSiteImpl.java
+@@ -0,0 +1,60 @@
++/*
++ * 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 impl.java.dyn;
++
++import java.dyn.*;
++
++/**
++ * The CallSite privately created by the JVM at every invokedynamic instruction.
++ * @author jrose
++ */
++class CallSiteImpl extends CallSite {
++ // Fields used only by the JVM. Do not use or change.
++ Object vmref;
++ long vmdata;
++
++ private CallSiteImpl(Class<?> caller, String name, MethodType type) {
++ super(caller, name, type);
++ }
++
++ @Override
++ public void setTarget(MethodHandle mh) {
++ checkTarget(mh);
++ if (MethodHandleImpl.JVM_SUPPORT)
++ MethodHandleImpl.linkCallSite(this, (MethodHandleImpl) mh);
++ else
++ super.setTarget(mh);
++ }
++
++ // this is the up-call from the JVM:
++ static CallSiteImpl makeSite(Class<?> caller, String name, MethodType type,
++ long vmdata) {
++ CallSiteImpl site = new CallSiteImpl(caller, name, type);
++ site.vmdata = vmdata;
++ System.out.println("DynCallSite: "+site);
++ return site;
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/DirectMethodHandle.java b/src/share/classes/impl/java/dyn/DirectMethodHandle.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/DirectMethodHandle.java
+@@ -0,0 +1,65 @@
++/*
++ * 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 impl.java.dyn;
++
++import java.dyn.*;
++import java.lang.reflect.Method;
++
++/**
++ * The flavor of method handle which emulates invokespecial or invokestatic.
++ * @author jrose
++ */
++class DirectMethodHandle extends MethodHandle {
++ //inherited oop vmtarget; // methodOop or virtual class/interface oop
++ private final int vmindex; // method index within interface
++
++ // Constructors in this class *must* be package scoped or private.
++ DirectMethodHandle(MethodType mt, Method m, boolean doDispatch) {
++ super(Access.TOKEN, mt);
++ this.vmindex = (doDispatch ? 0 : -1); // maybe updated by JVM
++ if (MethodHandleImpl.JVM_SUPPORT) {
++ this.vmtarget = null; // maybe updated by JVM
++ MethodHandleImpl.init(this, m, doDispatch);
++ } else {
++ this.vmtarget = m;
++ }
++ }
++
++ public boolean hasReceiverTypeDispatch() {
++ return (vmindex >= 0);
++ }
++
++ public Method targetMethod() {
++ return null;
++ }
++
++ public Class<?> targetClass() {
++ if (vmindex < 0)
++ return (Class<?>) vmtarget;
++ else
++ return targetMethod().getDeclaringClass();
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/MethodHandleImpl.java b/src/share/classes/impl/java/dyn/MethodHandleImpl.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/MethodHandleImpl.java
+@@ -0,0 +1,408 @@
++/*
++ * 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 impl.java.dyn;
++
++import impl.java.dyn.util.MethodHandleAdapter;
++import impl.java.dyn.util.MethodHandleInvoker;
++import impl.java.dyn.util.Wrappers;
++import java.dyn.*;
++import java.lang.reflect.AccessibleObject;
++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 MethodHandleImpl {
++
++ // Fields in MethodHandle:
++ private byte vmentry; // adapter stub or method entry point
++ //private int vmslots; // optionally, hoist type.form.vmslots
++ protected Object vmtarget; // VM-specific, class-specific target value
++ //MethodType type; // defined in MethodHandle
++
++ // These two dummy fields are present to force 'I' and 'J' signatures
++ // into this class's constant pool, so they can be transferred
++ // to vmentry when this class is loaded.
++ static final int INT_FIELD = 0;
++ static final long LONG_FIELD = 0;
++
++ // type is defined in java.dyn.MethodHandle, which is platform-independent
++
++ // vmentry (a void* field) is used *only* by by the JVM.
++ // The JVM adjusts its type to int or long depending on system wordsize.
++ // Since it is statically typed as neither int nor long, it is impossible
++ // to use this field from Java bytecode. (Please don't try to, either.)
++
++ // The vmentry is an assembly-language stub which is jumped to
++ // immediately after the method type is verified.
++ // For a direct MH, this stub loads the vmtarget's entry point
++ // and jumps to it.
++
++ /**
++ * VM-based method handles must have a security token.
++ * This security token can only be obtained by trusted code.
++ * Do not create method handles directly; use factory methods.
++ */
++ public MethodHandleImpl(Access token) {
++ Access.check(token);
++ }
++
++ /// 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 MethodHandleImpl perform virtual or interface dispatch?
++ * @param caller If not null, access-check relative to this class
++ * @return a DirectMethodHandle 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.changeParameterType(0, rcvc);
++ }
++ return makeDirect(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 MethodHandleImpl perform virtual or interface dispatch?
++ * @param caller If not null, access-check relative to this class
++ * @return a DirectMethodHandle to the given method, or null if it does not exist
++ */
++ public static
++ MethodHandle findMethod(Access token,
++ Method m, boolean doDispatch,
++ Class<?> caller) {
++ Access.check(token);
++ // FIXME: check permissions of 'caller'
++ MethodType mtype = MethodType.make(m);
++ return makeDirect(mtype, m, doDispatch);
++ }
++
++ private static
++ MethodHandle makeDirect(MethodType mtype, Method m, boolean doDispatch) {
++ return new DirectMethodHandle(mtype, m, doDispatch);
++ }
++
++ public static
++ MethodHandle accessField(Access token,
++ Field f, boolean isSetter,
++ Class<?> caller) {
++ Access.check(token);
++ // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
++ throw new UnsupportedOperationException("Not yet implemented");
++ }
++
++ public static
++ MethodHandle accessArrayElement(Access token,
++ Class<?> arrayClass, boolean isSetter,
++ Class<?> caller) {
++ Access.check(token);
++ if (!arrayClass.isArray())
++ throw new IllegalArgumentException("not an array: "+arrayClass);
++ // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array.
++ throw new UnsupportedOperationException("Not yet implemented");
++ }
++
++ /** Bind a predetermined first argument to the given direct method handle.
++ * Callable only from MethodHandles.
++ * @param token Proof that the caller has access to this package.
++ * @param mh Any direct method handle.
++ * @param receiver Receiver (or first static method argument) to pre-bind.
++ * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
++ */
++ public static
++ MethodHandle bindReceiver(Access token,
++ MethodHandle mh, Object receiver) {
++ Access.check(token);
++ if (mh instanceof DirectMethodHandle)
++ return new BoundMethodHandle((DirectMethodHandle)mh, receiver, 0);
++ return null; // let caller try something else
++ }
++
++ /** Bind a predetermined argument to the given arbitrary method handle.
++ * Callable only from MethodHandles.
++ * @param token Proof that the caller has access to this package.
++ * @param mh Any method handle.
++ * @param receiver Argument (which can be a boxed primitive) to pre-bind.
++ * @return a suitable BoundMethodHandle
++ */
++ public static
++ MethodHandle bindArgument(Access token,
++ MethodHandle mh, int argnum, Object receiver) {
++ Access.check(token);
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ public static MethodHandle convertArguments(Access token,
++ MethodHandle mh,
++ MethodType newType,
++ MethodType oldType) {
++ Access.check(token);
++ throw new UnsupportedOperationException("Not yet implemented");
++ }
++
++ public static
++ MethodHandle dropArguments(Access token, MethodHandle mh,
++ MethodType newType, int argnum) {
++ Access.check(token);
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ public static
++ MethodHandle makeGuardWithTest(Access token,
++ final MethodHandle test,
++ final MethodHandle target,
++ final MethodHandle fallback) {
++ Access.check(token);
++ return (new MethodHandleAdapter(target.type()) {
++ // Adjust test to accept a varargs list.
++ final MethodHandle vatest
++ = MethodHandles.spreadArguments(test,
++ MethodType.make(int.class, Object[].class));
++ final MethodHandleInvoker vatester
++ = MethodHandleInvoker.make(vatest.type());
++ @Override
++ public Object invoke_LV(Object... arguments) {
++ boolean z;
++ // If javac supports MethodHandle.invoke directly:
++ //z = vatest.invoke<boolean>(arguments);
++ // If javac does not support direct MH.invoke calls:
++ z = vatester.invoke_IL(vatest, arguments) != 0;
++ return (z ? target : fallback);
++ }
++ }).methodHandle();
++ }
++
++ public static
++ MethodHandle makeDispatcher(Access token, MethodHandle dispatcher, MethodType type) {
++ Access.check(token);
++ throw new UnsupportedOperationException("Not yet implemented");
++ }
++
++ /**
++ * Determine if the JVM verifier allows a value of type src to be
++ * passed to a formal parameter (or return variable) of type dest.
++ * Returns 1 if the verifier allows the types to match without conversion.
++ * Returns -1 if the types can be made to match by a JVM-supported adapter.
++ * Cases supported are:
++ * <ul><li>checkcast
++ * </li><li>conversion in either direction between int and a subword type
++ * </li><li>unboxing from a wrapper to its corresponding primitive type
++ * </li><li>conversion in either direction between float and double
++ * </li></ul>
++ * (Autoboxing is not supported here; it must be done via Java code.)
++ * Returns 0 otherwise.
++ */
++ static int canPassUnchecked(Class<?> src, Class<?> dest) {
++ if (src == dest)
++ return 1;
++
++ if (dest.isPrimitive()) {
++ if (dest == void.class)
++ // Return anything to a caller expecting void.
++ return 1;
++ if (src == void.class)
++ return 0; // void-to-something?
++ if (!src.isPrimitive())
++ // Cannot pass a reference to any primitive type (exc. void).
++ return 0;
++ boolean swt = Wrappers.isSubwordOrInt(src);
++ boolean dwt = Wrappers.isSubwordOrInt(dest);
++ if (swt && dwt) {
++ if (Wrappers.bitWidth(src) >= Wrappers.bitWidth(dest))
++ return -1; // truncation may be required
++ if (!Wrappers.isSigned(dest) && Wrappers.isSigned(src))
++ return -1; // sign elimination may be required
++ }
++ if (src == float.class || dest == float.class) {
++ if (src == double.class || dest == double.class)
++ return -1; // floating conversion may be required
++ else
++ return 0; // other primitive conversions NYI
++ } else {
++ // all fixed-point conversions are supported
++ return 0;
++ }
++ } else if (src.isPrimitive()) {
++ // Cannot pass a primitive to any reference type.
++ // (Maybe allow null.class?)
++ return 0;
++ }
++
++ // Handle reference types in the rest of the block:
++
++ // The verifier treats interfaces exactly like Object.
++ if (dest.isInterface()) dest = Object.class;
++ //if (src.isInterface()) src = Object.class;
++ if (dest == Object.class)
++ // pass any reference to object or an arb. interface
++ return 1;
++ // else it's a definite "maybe" (cast is required)
++ return -1;
++ }
++
++ protected static String basicToString(MethodHandle mh) {
++ String name = JVM_SUPPORT ? getMethodName(mh) : null;
++ if (name == null) name = "<unknown>";
++ return name + "/" + mh.type();
++ }
++
++ @Override
++ public String toString() {
++ return basicToString((MethodHandle)this);
++ }
++
++ /// The JVM interface for this package is all here:
++
++ /** Initialize the method handle to adapt the call. */
++ static native void init(AdapterMethodHandle self, MethodHandle target, int argnum);
++ /** Initialize the method handle to call the correct method, directly. */
++ static native void init(BoundMethodHandle self, Object target, int argnum);
++ /** Initialize the method handle to call as if by an invoke* instruction. */
++ static native void init(DirectMethodHandle self, Object refm, boolean doDispatch);
++
++ /** Initialize the method type form to participate in JVM calls.
++ * This is done once for each erased type.
++ */
++ public static void init(Access token, MethodType self) {
++ Access.check(token);
++ init(self);
++ }
++ static native void init(MethodType self);
++
++ /** Fetch the name of the handled method, if available.
++ * This routine is for debugging and reflection.
++ */
++ static String getMethodName(MethodHandleImpl self) {
++ return (String) getTarget(self, ETF_NAME);
++ }
++
++ /** Fetch the reflective version of the handled method, if available.
++ */
++ static AccessibleObject getTargetMethod(MethodHandleImpl self) {
++ return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
++ }
++
++ /** Fetch the target of this method handle.
++ * If it directly targets a method, return a tuple of method info.
++ * The info is of the form new Object[]{defclass, name, sig, refclass}.
++ * If it is chained to another method handle, return that handle.
++ */
++ static Object getTargetInfo(MethodHandleImpl self) {
++ return getTarget(self, ETF_HANDLE_OR_METHOD_INFO);
++ }
++
++ /** Tell the JVM that we need to change the target of an invokedynamic. */
++ static native void linkCallSite(CallSiteImpl site, MethodHandleImpl target);
++
++ /** Fetch the vmtarget field.
++ * It will be sanitized as necessary to avoid exposing non-Java references.
++ * This routine is for debugging and reflection.
++ */
++ static native Object getTarget(MethodHandleImpl self, int format);
++ static final int ETF_HANDLE_OR_METHOD_INFO = 0,
++ ETF_DIRECT_HANDLE = 1,
++ ETF_METHOD_INFO = 2,
++ ETF_REFLECT_METHOD = 3,
++ ETF_NAME = 4;
++ static final int MI_DECLARING_CLASS = 0,
++ MI_NAME = 1,
++ MI_SIGNATURE = 2,
++ MI_REFERENCE_CLASS = 3;
++
++ /** Fetch MH-related JVM parameter.
++ * which=0 retrieves MethodHandlePushLimit
++ * which=1 retrieves stack slot push size (in address units)
++ */
++ static native int getConstant(int which);
++
++ /** True iff this HotSpot JVM has built-in support for method handles.
++ * If false, some test cases might run, but functionality will be missing.
++ */
++ public static final boolean JVM_SUPPORT;
++
++ /** Java copy of MethodHandlePushLimit in range 2..255. */
++ static final int JVM_PUSH_LIMIT;
++ /** JVM stack motion (in words) after one slot is pushed, usually -1.
++ */
++ static final int JVM_STACK_MOVE_UNIT;
++
++ private static native void registerNatives();
++ static {
++ boolean JVM_SUPPORT_;
++ int JVM_PUSH_LIMIT_;
++ int JVM_STACK_MOVE_UNIT_;
++ try {
++ registerNatives();
++ JVM_SUPPORT_ = true;
++ JVM_PUSH_LIMIT_ = getConstant(0);
++ JVM_STACK_MOVE_UNIT_ = getConstant(1);
++ //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
++ } catch (UnsatisfiedLinkError ee) {
++ // ignore; if we use init() methods later we'll see linkage errors
++ JVM_SUPPORT_ = false;
++ JVM_PUSH_LIMIT_ = 3; // arbitrary
++ JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
++ }
++ JVM_SUPPORT = JVM_SUPPORT_;
++ JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
++ JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
++ if (!JVM_SUPPORT)
++ System.out.println("Warning: Running with JVM_SUPPORT=false");
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/package-info.java b/src/share/classes/impl/java/dyn/package-info.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/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 impl.java.dyn;
+diff --git a/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java b/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java
+@@ -0,0 +1,333 @@
++/*
++ * 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 impl.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 impl.java.dyn.util.Wrappers;
++import java.dyn.WrongMethodTypeException;
++import java.io.IOException;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++import java.util.IdentityHashMap;
++
++/**
++ * Emulation of method handle invocation.
++ * Not needed if javac supports direct invocation of MethodHandle.invoke.
++ * @author jrose
++ */
++public abstract
++class MethodHandleInvoker {
++ 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 of 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 int invoke_IL(MethodHandle mh, Object a0)
++ { throw wrongType(mh); }
++ public Object invoke_LL(MethodHandle mh, Object a0)
++ { throw wrongType(mh); }
++ public Object invoke_LI(MethodHandle mh, int 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_LI(int 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 LI extends MethodHandleInvoker {
++ static final int FINGERPRINT = fL | fI<<fA0;
++ public LI(MethodType type) { super(type); }
++ @Override public Object invoke_LI(MethodHandle mh, int a0) {
++ checkType(mh);
++ return ((FakeMethodHandle)mh).fake_invoke_LI(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 LI.FINGERPRINT: template = LI.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;
++ }
++ System.out.println("new invoker: "+inv);
++ 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 of 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 of 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/impl/java/dyn/util/Wrappers.java b/src/share/classes/impl/java/dyn/util/Wrappers.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/Wrappers.java
+@@ -0,0 +1,224 @@
++/*
++ * 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 impl.java.dyn.util;
++
++import java.util.HashMap;
++
++public class Wrappers {
++
++ private Wrappers() { } // cannot instantiate
++
++ public static <T> Class<T> asWrapperType(Class<T> type) {
++ if (!type.isPrimitive()) {
++ return type;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(type);
++ assert (memo != null);
++ return (Class<T>) memo[0]; // unchecked warning is OK here
++ }
++
++ public static <T> Class<T> asPrimitiveType(Class<T> type) {
++ if (type.isPrimitive()) {
++ return type;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(type);
++ if (memo == null) {
++ return type;
++ }
++ return (Class<T>) memo[1]; // unchecked warning is OK here
++ }
++
++ public static boolean isWrapperType(Class<?> type) {
++ return asPrimitiveType(type) != type;
++ }
++
++ public static char basicTypeChar(Class<?> type) {
++ if (!type.isPrimitive()) {
++ return 'L';
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(type);
++ assert (memo != null);
++ return (char) (Character) memo[2];
++ }
++
++ static final String PRIMITIVE_BITS_TABLE = "LZBCSFIZZDJ";
++ // "--012345678"
++
++ /** Return the number of bits in the given type, or zero for refs. */
++ public static int bitWidth(Class<?> type) {
++ return bitWidth(basicTypeChar(type));
++ }
++
++ /** Return the number of bits in the given basic type, or zero for refs. */
++ public static int bitWidth(char c) {
++ int i = PRIMITIVE_BITS_TABLE.indexOf(c);
++ if (i < 0) throw new IllegalArgumentException("not a basic type char: "+c);
++ i -= 2;
++ switch (i) {
++ case -2: return 0; // L
++ case -1: return 1; // Z
++ case 0: return 8; // B
++ default: return (i + (i & 1)) * 8;
++ }
++ }
++
++ /** Return the number of bits in the given type, or zero for refs. */
++ public static boolean isSigned(Class<?> type) {
++ return isSigned(basicTypeChar(type));
++ }
++
++ /** Return the number of bits in the given basic type, or zero for refs. */
++ public static boolean isSigned(char c) {
++ int i = PRIMITIVE_BITS_TABLE.indexOf(c);
++ assert(c != ' ' && (i >= 0 || c == 'L'));
++ return (i & 1) == 0;
++ }
++
++ /** Report if the type is one of int, boolean, byte, char, or short. */
++ public static boolean isSubwordOrInt(Class<?> type) {
++ return isSubwordOrInt(basicTypeChar(type));
++ }
++
++ /** Report if the type char is one of "IZBCS". */
++ public static boolean isSubwordOrInt(char c) {
++ return "IZBCS".indexOf(c) >= 0;
++ }
++
++ /** Return the primitive type that corresponds to the given bytecode
++ * signature character. Return {@code Object.class} for the character
++ * 'L', and null for any non-signature character or '['.
++ */
++ 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<?> type) {
++ if (!type.isPrimitive()) {
++ return null;
++ }
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(type);
++ assert (memo != null);
++ return memo[3];
++ }
++
++ public static <T> T wrap(Object x, Class<T> numClass) {
++ Class<T> primitiveType = asPrimitiveType(numClass);
++ return numClass.cast(wrap(x, basicTypeChar(primitiveType)));
++ }
++ public static Object wrap(Object x, char c) {
++ Number xn = numberValue(x);
++ switch (c) {
++ case 'I': return Integer.valueOf(xn.intValue());
++ case 'J': return Long.valueOf(xn.longValue());
++ case 'F': return Float.valueOf(xn.floatValue());
++ case 'D': return Double.valueOf(xn.doubleValue());
++ case 'S': return Short.valueOf((short) xn.intValue());
++ case 'B': return Byte.valueOf((byte) xn.intValue());
++ case 'C': return Character.valueOf((char) xn.intValue());
++ case 'Z': return Boolean.valueOf(boolValue(xn.longValue()));
++ case 'V': return null;
++ }
++ return xn;
++ }
++
++ private static Number numberValue(Object x) {
++ if (x instanceof Number) return (Number)x;
++ if (x instanceof Character) return (int)(Character)x;
++ if (x instanceof Boolean) return (Boolean)x ? 1 : 0;
++ // Remaining allowed case of void: Must be a null reference.
++ return (Number)x;
++ }
++ private static boolean boolValue(long bits) {
++ bits &= 1; // simple 31-bit zero extension
++ return (bits != 0);
++ }
++
++ 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);
++ }
++ }
++
++ // TO DO: Put these into a unit test.
++ private static Class<Integer> PTYPE = int.class, WTYPE = Integer.class;
++ static {
++ assert(PTYPE != WTYPE);
++ assert(asPrimitiveType(PTYPE) == PTYPE);
++ assert(asPrimitiveType(WTYPE) == PTYPE);
++ assert( asWrapperType(PTYPE) == WTYPE);
++ assert( asWrapperType(WTYPE) == WTYPE);
++
++ assert(bitWidth(String.class) == 0);
++ assert(bitWidth(Integer.class) == 0);
++ assert(bitWidth(int.class) == 32);
++ assert(bitWidth(char.class) == 16);
++ assert(bitWidth(short.class) == 16);
++ assert(bitWidth(byte.class) == 8);
++ assert(bitWidth(boolean.class) == 1);
++ assert(bitWidth(double.class) == 64);
++ assert(bitWidth(float.class) == 32);
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/util/package-info.java b/src/share/classes/impl/java/dyn/util/package-info.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/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 impl.java.dyn.util;
+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,116 @@
++/*
++ * 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>
++ * @author John Rose, JSR 292 EG
++ */
++public abstract class CallSite {
++ protected MethodHandle target;
++ protected final Object caller; // usually a class
++ protected final String name;
++ protected final MethodType type;
++
++ protected CallSite(Object caller, String name, MethodType type) {
++ this.caller = caller;
++ this.name = name;
++ this.type = type;
++ }
++
++ /**
++ * Report the current linkage state of the call site. (This is mutable.)
++ * The value is null if and only if the call site is currently unlinked.
++ * @return the current linkage state of the call site
++ */
++ public MethodHandle getTarget() {
++ return target;
++ }
++
++ /**
++ * Link or relink the call site, by setting its target method.
++ * @param target the new target, or null if it is to be unlinked
++ * @throws WrongMethodTypeException if the new target is not null
++ * and has a method type that differs from the call site type
++ */
++ public void setTarget(MethodHandle target) {
++ checkTarget(target);
++ this.target = target;
++ }
++
++ protected void checkTarget(MethodHandle target) {
++ if (!canSetTarget(target))
++ throw new WrongMethodTypeException(String.valueOf(target));
++ }
++
++ protected boolean canSetTarget(MethodHandle target) {
++ return (target == null || target.type() == type());
++ }
++
++ /**
++ * Report the class containing the call site.
++ * This is immutable static context.
++ * @return class containing the call site
++ */
++ public Class<?> callerClass() {
++ return (Class) caller;
++ }
++
++ /**
++ * Report the method name specified in the {@code invokedynamic} instruction.
++ * This is immutable static context.
++ * @return method name specified by the call site
++ */
++ public String name() {
++ return 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
++ */
++ public MethodType type() {
++ return type;
++ }
++
++ @Override
++ public String toString() {
++ return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
++ }
++}
+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,50 @@
++/*
++ * 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 to request javac to emit an {@code invokedynamic} instruction.
++ * A language compiler might use this interface to express invokedynamic instructions as follows:
++ * <blockquote><pre>
++ * Dynamic.greet("hello world", 123);
++ * // previous line generates invokedynamic "greet" "(Ljava/lang/String;I)Ljava/lang/Object;"
++ * Dynamic.<void>println(123);
++ * // previous line generates invokedynamic "println" "(I)V"
++ * Dynamic.#"long:strange:name"();
++ * // previous line generates invokedynamic "long:strange:name" "()Ljava/lang/Object;"
++ * </pre></blockquote>
++ * <p>
++ * 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.
++ * <p>
++ * This type may be used as a marker interface for arguments to method handles, in order
++ * to distinguish the static type {@code Object} from a dynamically typed reference.
++ * @author John Rose, JSR 292 EG
++ */
++public interface 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,211 @@
++/*
++ * 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 impl.java.dyn.util.MethodHandleInvoker;
++import java.util.WeakHashMap;
++import sun.reflect.Reflection;
++
++/**
++ * Static methods which control the linkage of invokedynamic call sites.
++ * @author John Rose, JSR 292 EG
++ */
++public class Linkage {
++ private Linkage() {} // do not instantiate
++
++ /**
++ * Register a bootstrap method for use for a given caller class.
++ * The method handle must be of a type equivalent to {@link Linkage#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.
++ */
++ public static
++ void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
++ Class callc = Reflection.getCallerClass(2);
++ checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
++ if (mh != null && mh.type() != BOOTSTRAP_METHOD_TYPE)
++ throw new WrongMethodTypeException(mh.type().toString());
++ synchronized (bootstrapMethods) {
++ if (bootstrapMethods.containsKey(callerClass))
++ throw new IllegalStateException("bootstrap method already declared in "+callerClass);
++ bootstrapMethods.put(callerClass, mh);
++ }
++ }
++
++ /**
++ * Report the bootstrap method registered for a given class.
++ * Returns null if the class has never yet registered a bootstrap method,
++ * or if the class has explicitly registered a null bootstrap method.
++ * Only callers privileged to set the bootstrap method may inquire
++ * about it, because a bootstrap method is potentially a back-door entry
++ * points to its class.
++ */
++ public static
++ MethodHandle getBootstrapMethod(Class callerClass) {
++ Class callc = Reflection.getCallerClass(2);
++ checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
++ synchronized (bootstrapMethods) {
++ return bootstrapMethods.get(callerClass);
++ }
++ }
++
++ /** The type of any bootstrap method is (CallSite,Object...)Object.
++ * The varargs marker is required.
++ */
++ public static final MethodType BOOTSTRAP_METHOD_TYPE
++ = MethodType.make(Object.class,
++ CallSite.class, Object[].class).changeVarArgs(true);
++
++ private static MethodHandleInvoker bootstrapMethodInvoker;
++
++ private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
++ new WeakHashMap<Class, MethodHandle>();
++
++ /** 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) {
++ Class callerClass = site.callerClass();
++ MethodHandle mh;
++ synchronized (bootstrapMethods) {
++ mh = bootstrapMethods.get(callerClass);
++ }
++ if (mh == null)
++ throw new IllegalStateException("no bootstrap method declared in "+callerClass);
++
++ System.out.println(site+": calling bootstrap "+mh);
++ if (bootstrapMethodInvoker == null)
++ bootstrapMethodInvoker = MethodHandleInvoker.make(BOOTSTRAP_METHOD_TYPE);
++ return bootstrapMethodInvoker.invoke_LLL(mh, site, receiverAndArguments);
++ }
++
++ /**
++ * 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");
++ }
++
++ /**
++ * Ensure the requesting class have privileges to perform invokedynamic
++ * linkage operations on subjectClass. True if requestingClass is
++ * null (meaning the request originates from the JVM) or if the
++ * classes are in the same package and have consistent class loaders.
++ * (The subject class loader must be identical with or be a child of
++ * the requesting class loader.)
++ * @param requestingClass
++ * @param subjectClass
++ * @return
++ */
++ static void checkPackagePrivilege(Class requestingClass, Class subjectClass,
++ String permissionName) {
++ if (requestingClass == null) return;
++ if (requestingClass == subjectClass) return;
++ SecurityManager security = System.getSecurityManager();
++ if (security == null) return; // open season
++ ClassLoader rcl = requestingClass.getClassLoader();
++ ClassLoader scl = subjectClass.getClassLoader();
++ if (isParent(rcl, scl)) {
++ String rn = requestingClass.getName();
++ if (rn.startsWith("java.dyn.")) return;
++ String sn = subjectClass.getName();
++ if (samePackage(rn, sn)) return;
++ }
++ security.checkPermission(new LinkagePermission(permissionName, requestingClass));
++ }
++
++ static
++ MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
++ if (searchBootstrapClass != null) throw new UnsupportedOperationException("NYI");
++ MethodHandle mh = getBootstrapMethod(callerClass);
++ System.out.println("reporting bootstrap method to JVM: "+mh);
++ return mh;
++ }
++
++ private static boolean isParent(ClassLoader rcl, ClassLoader scl) {
++ while (scl != null && scl != rcl)
++ scl = scl.getParent();
++ return (scl == rcl);
++ }
++
++ private static boolean samePackage(String rn, String sn) {
++ assert((rn.indexOf('/') & sn.indexOf('/')) < 0); // no bytecode names
++ int lastDot = rn.lastIndexOf('.');
++ if (lastDot != sn.lastIndexOf('.')) return false;
++ return rn.startsWith(sn.substring(0, lastDot+1));
++ }
++
++}
+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 John Rose, JSR 292 EG
++ */
++
++public final class LinkagePermission extends BasicPermission {
++ /**
++ * Create a new LinkagePermission with the given name.
++ * The name is the symbolic name of the LinkagePermission, such as
++ * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
++ * may appear at the end of the name, following a ".", or by itself, to
++ * signify a wildcard match.
++ *
++ * @param name the name of the LinkagePermission
++ */
++ public LinkagePermission(String name) {
++ super(name);
++ }
++
++ /**
++ * Create a new LinkagePermission with the given name on the given class.
++ * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
++ *
++ * @param name the name of the LinkagePermission
++ * @param clazz the class affected by the permission
++ */
++ public LinkagePermission(String name, Class<?> clazz) {
++ super(name + "." + clazz.getName());
++ }
++}
+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,129 @@
++/*
++ * 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 impl.java.dyn.*;
++
++/**
++ * A method handle is a typed reference to the entry point of a method.
++ * <p>
++ * Method handles are strongly typed according to signature.
++ * They are not distinguished by method name or enclosing class.
++ * A method handle must be invoked under a signature which exactly matches
++ * the method handle's own type.
++ * <p>
++ * Every method handle confesses its type via the <code>type</code> accessor.
++ * The structure of this type is a series of classes, one of which is
++ * the return type of the method (or <code>void.class</code> if none).
++ * <p>
++ * Every method handle appears as an object containing a method named
++ * <code>invoke</code>, whose signature exactly matches
++ * the method handle's type.
++ * A normal Java method call (using the <code>invokevirtual</code> instruction)
++ * can invoke this method from Java source code (if language support is present).
++ * <p>
++ * Every call to a method handle specifies an intended method type,
++ * which must exactly match the type of the method handle.
++ * (The type is specified in the <code>invokevirtual</code> instruction,
++ * via a {@code CONSTANT_NameAndType} constant pool entry.)
++ * The call looks within the receiver object for a method
++ * named <code>invoke</code> of the intended method type.
++ * The call fails with a {@link WrongMethodTypeException}
++ * if the method does not exist, even if there is an <code>invoke</code>
++ * method of a closely similar signature.
++ * <p>
++ * A method handle is an unrestricted capability to call a method.
++ * A method handle can be formed on a non-public method by a class
++ * that has access to that method; the resulting handle can be used
++ * in any place by any caller who receives a reference to it. Thus, access
++ * checking is performed when the method handle is created, not
++ * (as in reflection) every time it is called. Handles to non-public
++ * methods, or in non-public classes, should generally be kept secret.
++ * They should not be passed to untrusted code.
++ * <p>
++ * Bytecode in an extended JVM can directly call a method handle's
++ * <code>invoke</code> from an <code>invokevirtual</code> instruction.
++ * The receiver class type must be <code>MethodHandle</code> and the method name
++ * must be <code>invoke</code>. The signature of the invocation
++ * (after resolving symbolic type names) must exactly match the method type
++ * of the target method.
++ * <p>
++ * Bytecode in an extended JVM can directly obtain a method handle
++ * for any accessible method from a <code>ldc</code> instruction
++ * which refers to a <code>CONSTANT_Methodref</code> or
++ * <code>CONSTANT_InterfaceMethodref</code> constant pool entry.
++ * <p>
++ * All JVMs can also use a reflective API called <code>MethodHandles</code>
++ * for creating and calling method handles.
++ * <p>
++ * A method reference may refer either to a static or non-static method.
++ * In the non-static case, the method handle type includes an explicit
++ * receiver argument, prepended before any other arguments.
++ * In the method handle's type, the initial receiver argument is typed
++ * according to the class under which the method was initially requested.
++ * (E.g., if a non-static method handle is obtained via <code>ldc</code>,
++ * the type of the receiver is the class named in the constant pool entry.)
++ * <p>
++ * When a method handle to a virtual method is invoked, the method is
++ * always looked up in the receiver (that is, the first argument).
++ * <p>
++ * A non-virtual method handles to a specific virtual method implementation
++ * can also be created. These do not perform virtual lookup based on
++ * receiver type. Such a method handle simulates the effect of
++ * an <code>invokespecial</code> instruction to the same method.
++ *
++ * @see MethodType
++ * @see MethodHandles
++ * @author John Rose, JSR 292 EG
++ */
++public class MethodHandle extends MethodHandleImpl {
++ // interface MethodHandle<T extends MethodType<R,A...>>
++ // { T type(); <R,A...> public R invoke(A...); }
++
++ final private MethodType type;
++
++ /**
++ * Report the type of this method handle.
++ * Every invocation of this method handle must exactly match this type.
++ * @return the method handle type
++ */
++ public MethodType type() {
++ return type;
++ }
++
++ /**
++ * The constructor for MethodHandle may only be called by privileged code.
++ * Subclasses may be in other packages, but must possess
++ * a token which they obtained from MH with a security check.
++ * @param token non-null object which proves access permission
++ * @param type type (permanently assigned) of the new method handle
++ */
++ protected MethodHandle(Access token, MethodType type) {
++ super(token);
++ this.type = type;
++ }
++}
+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,714 @@
++/*
++ * 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 impl.java.dyn.util.Wrappers;
+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.*;
++import impl.java.dyn.*;
++import java.util.Arrays;
++import java.util.List;
+
+/**
+ * Fundamental operations and utilities for MethodHandle.
@@ -183,13 +2510,13 @@ new file mode 100644
+ * which Java generic types cannot range over.</li>
+ * <li>Method types can optionally specify varargs (ellipsis).</li>
+ * </ol>
-+ * @author jrose
++ * @author John Rose, JSR 292 EG
+ */
+public class MethodHandles {
+
+ private MethodHandles() { } // do not instantiate
+
-+ private static final Access TOKEN = Access.getToken();
++ private static final Access IMPL_TOKEN = Access.getToken();
+
+ //// Method handle creation from ordinary methods.
+
@@ -201,11 +2528,13 @@ new file mode 100644
+ * @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) {
++ * @exception SecurityException <em>TBD</em>
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findMethod(TOKEN, defc, name, null, type, false, callc);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, null, type, false, callc);
+ }
+
+ /**
@@ -223,32 +2552,65 @@ new file mode 100644
+ * @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) {
++ * @exception SecurityException <em>TBD</em>
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
+ 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,
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, defc, type, true, callc);
++ }
++
++ /**
++ * Produce an early-bound method handle for a virtual method,
++ * or a handle for a constructor.
++ * The type of the method handle will be that of the method or constructor,
+ * with the receiver type (<code>defc</code>) prepended.
-+ * The method and all its argument types must be accessible to the caller.
++ * The method or constructor and all its argument types must be accessible
++ * to the caller, according to the rules of the
++ * <code>invokespecial</code> instruction.
+ * <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, or "<init>" for a constructor
++ * @param type the type of the method, with the receiver argument omitted
++ * @return the desired method handle, or null if no such method exists
++ * @exception SecurityException <em>TBD</em>
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle findSpecial(Class<?> defc, String name, MethodType type) throws NoAccessException {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, defc, type, false, callc);
++ }
++
++ /**
++ * Produce an early-bound method handle for a non-static method.
++ * The type of the method handle will be that of the method.
++ * The given receiver will be bound into the method handle.
++ * The method and all its argument types must be accessible to the caller.
++ * <p>
++ * Equivalent <em>(with caveats TBD about accessibility of the receiver's type)</em>
++ * to the following expression:
++ * <code>
++ * {@link #insertArgument}({@link #findVirtual}(receiver.getClass(), name, type), receiver)
++ * </code>
++ * @param receiver the object from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
+ * @return the desired method handle, or null if no such method exists
-+ */
-+ public static
-+ MethodHandle findSpecial(Class<?> defc, String name, MethodType type) {
++ * @exception SecurityException <em>TBD</em>
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findMethod(TOKEN, defc, name, defc, type, false, callc);
++ Class<?> defc = receiver.getClass();
++ MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, defc, type, true, callc);
++ return insertArgument(dmh, receiver);
+ }
+
+ /**
@@ -263,11 +2625,12 @@ new file mode 100644
+ * 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) {
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle unreflect(Method m) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findMethod(TOKEN, m, true, callc);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, m, true, callc);
+ }
+
+ /**
@@ -281,14 +2644,16 @@ new file mode 100644
+ * 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) {
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle unreflectSpecial(Method m) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findMethod(TOKEN, m, false, callc);
-+ }
-+
-+ /**
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, m, false, callc);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle giving read access to a reflected field.
+ * The type of the method handle will have a return type of the field's
+ * value type. Its sole argument will be the field's containing class
@@ -297,14 +2662,16 @@ new file mode 100644
+ * 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) {
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle unreflectGetter(Field f) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findField(TOKEN, f, false, (Class)callc);
-+ }
-+
-+ /**
++ return MethodHandleImpl.accessField(IMPL_TOKEN, f, false, (Class)callc);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle giving write access to a reflected field.
+ * The type of the method handle will have a void return type.
+ * Its last argument will be the field's value type.
@@ -314,31 +2681,50 @@ new file mode 100644
+ * 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) {
++ * @exception NoAccessException if access checking fails
++ */
++ public static
++ MethodHandle unreflectSetter(Field f) throws NoAccessException {
+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MH.findField(TOKEN, f, true, (Class)callc);
-+ }
++ return MethodHandleImpl.accessField(IMPL_TOKEN, f, true, (Class)callc);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle giving read access to elements of an array.
++ * The type of the method handle will have a return type of the array's
++ * element type. Its first argument will be the array type,
++ * and the second will be {@code int}.
++ * @param arrayClass an array type
++ * @return a method handle which can load values from the given array type
++ * @throws IllegalArgumentException if arrayClass is not an array type
++ */
++ public static
++ MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false, (Class)callc);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle giving write access to elements of an array.
++ * The type of the method handle will have a void return type.
++ * Its last argument will be the array's element type.
++ * The first and second arguments will be the array type and int.
++ * @return a method handle which can store values into the array type
++ * @throws IllegalArgumentException if arrayClass is not an array type
++ */
++ public static
++ MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, 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;
-+ }
-+
-+ /**
++ * <em>WORK IN PROGRESS:</em>
+ * Perform value checking, exactly as if for an adapted method handle.
+ * It is assumed that the given value is either null, of type T0,
+ * or (if T0 is primitive) of the wrapper type corresponding to T0.
@@ -422,164 +2808,57 @@ new file mode 100644
+ 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.
++ Class<?> T0;
++ if (value == null)
++ T0 = Object.class;
++ else
++ T0 = value.getClass();
++ return checkValue(T0, T1, value);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion,
++ * and/or varargs conversion.
++ * The original type and new type must have the same number of
++ * arguments, or else one or both them the must be varargs types.
+ * The resulting method handle is guaranteed to confess a type
-+ * which is equal to the desired 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> &mdash; the <i>N</i>th incoming argument ($0 is first)
-+ * <li>$<i>N</i>/<i>I</i> &mdash; the <i>I</i>th array element of $<i>N</i>
-+ * <li>$V &mdash; the values argument passed to this method
-+ * <li>$V/<i>I</i> &mdash; the <i>I</i>th array element of $V
-+ * <li>!$<i>N</i>/<i>L</i> &mdash; 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>} &mdash; 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>} &mdash; 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>} &mdash; 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 &mdash; a zero or null of the expected argument type
-+ * <li>$X<i>X</i> &mdash; an integer hexadecimal constant is passed
-+ * <li>$N &mdash; the new method handle itself is passed
-+ * <li>$M &mdash; the original method handle itself is passed
-+ * <li>*<i>D</i> &mdash; 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> &mdash; 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> &mdash; 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.
++ * which is equal to the desired new type, with any varargs property erased.
+ * <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:
++ * arguments and return types. Let T0 and T1 be the differing
++ * new and old parameter types (or old and new return types)
++ * for corresponding values passed by the new and old method types.
++ * <p>
++ * If an ordinary (non-varargs) parameter of the new type is
++ * to be boxed in a varargs parameter of the old type of type T1[],
++ * then T1 is the element type of the varargs array.
++ * Otherwise, if a varargs parameter of the new type of type T0[]
++ * is to be spread into one or more outgoing old type parameters,
++ * then T0 is the element type of the
++ * If the new type is varargs and the old type is not, the varargs
++ * argument will be checked and must be a non-null array of exactly
++ * the right length. If there are no parameters in the old type
++ * corresponding to the new varargs parameter, the varargs argument
++ * is also allowed to be null.
++ * <p>
++ * Given those types T0, T1, one of the following conversions is applied
++ * if possible:
+ * <ul>
-+ * <li>If T0 and T1 are references, then a cast to T1 is applied.
-+ * (The types do not need to be related in any particular way.)
++ * <li>If T0 and T1 are references, then a cast to T2 is applied,
++ * where T2 is Object if T1 is an interface, else T1.
++ * (The types do not need to be related in any particular way.
++ * The treatment of interfaces follows the usage of the bytecode verifier.)
+ * <li>If T0 and T1 are primitives, then a Java casting
+ * conversion (JLS 5.5) is applied, if one exists.
-+ * <li>If T0 and T1 are primitives and one is boolean 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 and T1 are primitives and one is boolean,
++ * the boolean is treated as a one-bit unsigned integer.
++ * (This treatment follows the usage of the bytecode verifier.)
++ * A conversion from another primitive type behaves as if
++ * it first converts to byte, and then masks all but the low bit.
+ * <li>If T0 is a primitive and T1 a reference, a boxing
+ * conversion is applied if one exists, possibly followed by
+ * an reference conversion to a superclass.
@@ -595,23 +2874,27 @@ new file mode 100644
+ * 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 T1 is void, any returned value is discarded
+ * <li>If T0 is void and T1 a reference, a null value is introduced.
+ * <li>If T0 is void and T1 a primitive, a zero value is introduced.
+ * </ul>
+ * @param mh the method handle to invoke after arguments are retyped
+ * @param newType the expected type of the new method handle
-+ * @return
++ * @return a method handle which delegates to {@code mh} after performing
++ * any necessary argument conversions, and arranges for any
++ * necessary return value conversions
+ */
+ public static
+ MethodHandle convertArguments(MethodHandle mh, MethodType newType) {
+ MethodType oldType = mh.type();
+ if (oldType.equals(newType))
+ return mh;
-+ return adaptArguments(mh, newType, "*$0");
-+ }
-+
-+ /**
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh,
++ newType, mh.type());
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which adapts the type of the
+ * given method handle to a new type, by spreading the final argument.
+ * The resulting method handle is guaranteed to confess a type
@@ -647,30 +2930,20 @@ new file mode 100644
+ 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());
-+ }
-+
-+ /**
++ throw newIllegalArgumentException("wrong number of arguments");
++ newType = newType.changeVarArgs(true);
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, newType, oldType);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which adapts the type of the
+ * given method handle to a new type, by collecting a series of
+ * trailing arguments into an array.
+ * The resulting method handle is guaranteed to confess a type
+ * which is equal to the desired new type.
+ * <p>
-+ * This method is inverse to {@link spreadArguments}.
++ * 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
@@ -689,23 +2962,13 @@ new file mode 100644
+ 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());
-+ }
-+
-+ /**
++ throw newIllegalArgumentException("wrong number of arguments");
++ oldType = oldType.changeVarArgs(true);
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, newType, oldType);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * 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
@@ -719,6 +2982,7 @@ new file mode 100644
+ }
+
+ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * 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
@@ -733,6 +2997,7 @@ new file mode 100644
+ }
+
+ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which calls the original method handle,
+ * after inserting the given argument at the given position.
+ * The type of the new method handle will drop the corresponding argument
@@ -760,85 +3025,106 @@ new file mode 100644
+ int outargs = oldType.parameterCount();
+ int inargs = outargs - 1;
+ if (pos < 0 || pos >= outargs)
-+ throw new IllegalArgumentException("no argument type to append");
++ throw newIllegalArgumentException("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);
++ MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_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);
-+ }
-+
-+ /**
++ return MethodHandleImpl.bindArgument(IMPL_TOKEN, mh, pos, value);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which calls the original method handle,
-+ * after dropping the given argument at the given position.
++ * after dropping the given argument(s) 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.
++ * type(s), at that position, into the original handle's type.
+ * <p>
+ * The <i>pos</i> may range between zero and <i>N-1</i>,
+ * where <i>N</i> is the number of argument types in <i>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 valueTypes the type(s) of the argument to drop
+ * @param pos which argument to drop (zero for the first)
+ * @return a new method handle which drops an argument of the given type,
+ * before calling the original method handle
+ */
+ public static
-+ MethodHandle dropArgument(MethodHandle mh, Class<?> valueType, int pos) {
++ MethodHandle dropArguments(MethodHandle mh, int pos, Class<?>... valueTypes) {
++ if (valueTypes.length == 0) return mh;
+ MethodType oldType = mh.type();
++ int outargs = oldType.parameterCount();
++ int inargs = outargs + valueTypes.length;
++ if (pos < 0 || pos >= inargs)
++ throw newIllegalArgumentException("no argument type to remove");
+ ArrayList<Class<?>> ptypes =
+ new ArrayList<Class<?>>(oldType.parameterList());
-+ 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);
++ ptypes.addAll(pos, Arrays.asList(valueTypes));
+ 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);
-+ }
++ return MethodHandleImpl.dropArguments(IMPL_TOKEN, mh, newType, pos);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Make a method handle which adapts a target method handle,
++ * by guarding it with a test, a boolean-valued method handle.
++ * If the guard fails, a fallback handle is called instead.
++ * All three method handles must have the same corresponding
++ * argument and return types, except that the return type
++ * of the test must be boolean.
++ * @param test method handle used for test, must return boolean
++ * @param target method handle to call if test passes
++ * @param fallback method handle to call if test fails
++ * @return method handle which incorporates the specified if/then/else logic
++ * @throws IllegalArgumentException if {@code test} does not return boolean,
++ * or if all three method types do not match (with the return
++ * type of {@code test} changed to match that of {@code target}).
++ */
++ public static
++ MethodHandle guardWithTest(MethodHandle test,
++ MethodHandle target,
++ MethodHandle fallback) {
++ if (target.type() != fallback.type())
++ throw newIllegalArgumentException("target and fallback types do not match");
++ if (target.type().changeReturnType(boolean.class) != test.type())
++ throw newIllegalArgumentException("target and test types do not match");
++ return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Make a method handle which dynamically computes a target method handle,
++ * and then tail-recursively invokes that computed method handle.
++ * The dispatcher handle must have the same argument types as the
++ * final method type, but must return {@link MethodHandle} instead of
++ * the ultimate return type. The returned method handle, in turn,
++ * is required to have exactly the given final method type.
++ * @param dispatcher method handle to call initiallly
++ * @param type type of the desired method handle, and also of the method
++ * handle returned by the dispatcher
++ * @return method handle which incorporates the specified dispatch logic
++ * @throws IllegalArgumentException if {@code dispatcher} does not itself
++ * return a method handle, or does not have the same argument type
++ * as {@code type}
++ */
++ public static
++ MethodHandle makeDispatcher(MethodHandle dispatcher, MethodType type) {
++ if (dispatcher.type().changeReturnType(MethodHandle.class) != type)
++ throw newIllegalArgumentException("target and test types do not match");
++ return MethodHandleImpl.makeDispatcher(IMPL_TOKEN, dispatcher, type);
++ }
++
++ static RuntimeException newIllegalArgumentException(String message) {
++ return new IllegalArgumentException(message);
++ }
++
+
+ /// standard method handles
+
@@ -847,15 +3133,15 @@ new file mode 100644
+ * @param x an arbitrary reference value
+ * @return the same value x
+ */
-+ public static <T>
++ /*public*/ static <T>
+ T identity(T x) {
+ return x;
+ }
+
+ /**
-+ * A method handle for {@link identity}
-+ */
-+ public static
++ * A method handle for {@link #identity}
++ */
++ /*public*/ static
+ MethodHandle identityMethod() {
+ if (IDENTITY == null)
+ IDENTITY = findStatic(MethodHandle.class, "identity", IDENTITY_TYPE);
@@ -869,14 +3155,14 @@ new file mode 100644
+ /**
+ * Empty function.
+ */
-+ public static
++ /*public*/ static
+ void empty() {
+ }
+
+ /**
-+ * A method handle for {@link empty}
-+ */
-+ public static
++ * A method handle for {@link #empty}
++ */
++ /*public*/ static
+ MethodHandle emptyMethod() {
+ if (EMPTY == null)
+ EMPTY = findStatic(MethodHandle.class, "empty", EMPTY_TYPE);
@@ -891,7 +3177,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/MethodType.java
-@@ -0,0 +1,553 @@
+@@ -0,0 +1,640 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -919,6 +3205,7 @@ new file mode 100644
+
+package java.dyn;
+
++import impl.java.dyn.util.Wrappers;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
@@ -926,6 +3213,7 @@ new file mode 100644
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
++import impl.java.dyn.*;
+
+/**
+ * Run-time token used to match call sites with method handles.
@@ -937,7 +3225,7 @@ new file mode 100644
+ * <p>
+ * This type can be created only by factory methods, which manage interning.
+ *
-+ * @author jrose
++ * @author John Rose, JSR 292 EG
+ */
+public final
+class MethodType {
@@ -945,6 +3233,8 @@ new file mode 100644
+ final Class<?>[] ptypes;
+ MethodTypeForm form; // erased form, plus cached data about primitives
+ MethodType wrapAlt; // alternative wrapped/unwrapped version
++
++ private static final Access IMPL_TOKEN = Access.getToken();
+
+ private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean varargs) {
+ this.rtype = rtype;
@@ -990,19 +3280,19 @@ new file mode 100644
+ return makeImpl(rtype, ptypes, varargs, false);
+ }
+
-+ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}. */
++ /** 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<?>[])}. */
++ /** 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<?>[])}.
++ return makeImpl(rtype, append(ptype0, ptypes), false, false);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+ * The resulting method has no parameter types.
+ */
+ public static
@@ -1010,7 +3300,7 @@ new file mode 100644
+ return makeImpl(rtype, NO_PTYPES, false, true);
+ }
+
-+ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+ * The resulting method has the single given parameter type.
+ */
+ public static
@@ -1018,7 +3308,7 @@ new file mode 100644
+ return makeImpl(rtype, new Class<?>[]{ ptype0 }, false, true);
+ }
+
-+ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ /** 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.
+ */
@@ -1046,9 +3336,13 @@ new file mode 100644
+ }
+ if (!trusted)
+ // defensively copy the array passed in by the user
-+ ptypes = ptypes.clone();
++ mt1 = new MethodType(rtype, ptypes.clone(), varargs);
+ // promote the object to the Real Thing, and reprobe
+ mt1.form = MethodTypeForm.findForm(mt1, varargs);
++ if (MethodHandleImpl.JVM_SUPPORT) {
++ if (mt1.form.erasedType == mt1)
++ MethodHandleImpl.init(IMPL_TOKEN, mt1);
++ }
+ assert(mt1.isVarArgs() == varargs);
+ synchronized (internTable) {
+ mt0 = internTable.get(mt1);
@@ -1059,19 +3353,394 @@ new file mode 100644
+ return mt1;
+ }
+
-+ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class<?>[])}.
++ 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 changed
++ */
++ public MethodType changeParameterType(int num, Class<?> nptype) {
++ if (parameterType(num) == nptype) return this;
++ Class<?>[] nptypes = ptypes.clone();
++ nptypes[num] = nptype;
++ return makeImpl(rtype, nptypes, isVarArgs(), true);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
++ * @param num the position (zero-based) of the inserted parameter type
++ * @param nptype a new parameter type to insert into the parameter list
++ * @return the same type, except with the selected parameter inserted
++ */
++ public MethodType insertParameterType(int num, Class<?> nptype) {
++ int len = ptypes.length;
++ Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
++ System.arraycopy(nptypes, num, nptypes, num+1, len-num);
++ nptypes[num] = nptype;
++ return makeImpl(rtype, nptypes, isVarArgs(), true);
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
++ * @param num the index (zero-based) of the parameter type to remove
++ * @return the same type, except with the selected parameter removed
++ */
++ public MethodType deleteParameterType(int num) {
++ int len = ptypes.length;
++ Class<?>[] nptypes;
++ if (num == 0) {
++ nptypes = Arrays.copyOfRange(ptypes, 1, len);
++ } else {
++ nptypes = Arrays.copyOfRange(ptypes, 0, len-1);
++ System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num);
++ }
++ return makeImpl(rtype, nptypes, 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 changeReturnType(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 changeVarArgs(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.erasedType;
++ }
++
++ /** 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 erasedType and primitives wrapped
++ */
++ public MethodType eraseWrap() {
++ return form.wrappedType;
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
++ * Convert all types, both reference and primitive, to Object.
++ * @return a version of the original type with all types replaced
++ * @see #makeGeneric(int)
++ */
++ public MethodType generic() {
++ return form.wrappedType.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--;
++ }
++ }
++
++ /// Queries which have to do with the bytecode architecture
++
++ /** The number of JVM stack slots required to invoke a method
++ * of this type. Note that (for historic reasons) the JVM requires
++ * a second stack slot to pass long and double arguments.
++ * So this method returns {@link #parameterCount()} plus the
++ * number of long and double parameters (if any).
++ * @return the number of JVM stack slots for this type's parameters
++ */
++ public int parameterSlotCount() {
++ return form.parameterSlotCount();
++ }
++
++ /** The JVM stack slot which carries the given parameter.
++ * The last parameter ({@link #parameterCount()}-1) is carried in the
++ * the most shallowly stacked argument slot, which is numbered as slot zero.
++ * The first parameter is carried in the most deeply stacked argument slot,
++ * which is {@link #parameterSlotCount()} minus the number of slots used
++ * by that parameter.
++ * <p>
++ * As a useful edge case, {@code parameterSlot(-1)} returns
++ * {@link #parameterSlotCount()}. No other negative values are accepted.
++ * <p>
++ * In general, the number returned is the number of arguments <em>after</em>
++ * the given parameter, <em>plus</em> the number of long or double arguments
++ * after the argument for the given parameter.
++ * @param num the index (zero-based) of the desired parameter type
++ * @return the index of the (shallowest) JVM stack slot transmitting the
++ * given parameter
++ */
++ public int parameterSlot(int num) {
++ return form.parameterToArgSlot(num);
++ }
++
++ /** The number of JVM stack slots required to receive a return value
++ * from a method of this type.
++ * If the {@link #returnType() return type} is void, it will be zero,
++ * else if the return type is long or double, it will be two, else one.
++ * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
++ */
++ public int returnSlotCount() {
++ return form.returnSlotCount();
++ }
++
++ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
+ * Find or create an instance (interned) of the given method type.
++ * Any class or interface name embedded in the signature string
++ * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
++ * on the given loader (or if it is null, on the system class loader).
+ * <p>
-+ * <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.
++ * Note that it is possible to build method types which cannot be
++ * constructed by this method, because their component types are
++ * not all reachable from a common class loader.
+ * @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) {
++ * @throws IllegalArgumentException if the string is not well-formed
++ * @throws TypeNotPresentException if a named type cannot be found
++ */
++ public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
++ throws IllegalArgumentException, TypeNotPresentException
++ {
+ if (loader == null)
+ loader = ClassLoader.getSystemClassLoader();
+ String str = bytecodeSignature;
@@ -1094,6 +3763,9 @@ new file mode 100644
+ }
+
+ /** Create a bytecode signature representation of the type.
++ * Note that this is not a strict inverse of
++ * {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)},
++ * because the latter requires a suitable class loader argument.
+ * @return the bytecode signature representation
+ */
+ public String toBytecodeString() {
@@ -1119,11 +3791,9 @@ new file mode 100644
+ 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;
++ throw new TypeNotPresentException(name, ex);
+ }
+ } else if (c == '[') {
+ Class<?> t = parseSig(str, i, loader);
@@ -1147,309 +3817,12 @@ new file mode 100644
+ }
+ }
+
-+
-+ 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,272 @@
+@@ -0,0 +1,271 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1477,8 +3850,7 @@ new file mode 100644
+
+package java.dyn;
+
-+//import java.dyn.emu.*;
-+import java.dyn.impl.*;
++import impl.java.dyn.util.Wrappers;
+
+/**
+ * Shared information for a group of method types, which differ
@@ -1491,28 +3863,26 @@ new file mode 100644
+ * 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
++ * @author John Rose
+ */
-+public class MethodTypeForm extends MTForm {
++class MethodTypeForm {
+ final int[] argToSlotTable, slotToArgTable;
+ final long argCounts; // packed slot & value counts
+ final long primCounts; // packed prim & double counts
+ final boolean varargs; // is this a "..." type?
-+ final MethodType erase; // the canonical erasure
-+ final MethodType wrap; // erasure, with primitives wrapped
-+
-+ private static final Access TOKEN = Access.getToken();
++ final int vmslots; // total number of parameter slots
++ final MethodType erasedType; // the canonical erasure
++ final MethodType wrappedType; // erasure, with primitives wrapped
+
+ public static MethodTypeForm of(MethodType type) {
+ return type.form;
+ }
+
+ private MethodTypeForm(MethodType erase, boolean varargs) {
-+ super(TOKEN);
-+ this.erase = erase;
++ this.erasedType = erase;
+ this.varargs = varargs;
+ MethodType wt = canonType(erase, WRAP);
-+ this.wrap = (wt == null) ? erase : wt;
++ this.wrappedType = (wt == null) ? erase : wt;
+
+ int ptypeCount = erase.ptypes.length;
+ int pslotCount = ptypeCount; // temp. estimate
@@ -1549,13 +3919,14 @@ new file mode 100644
+ if (lac != 0) {
+ int slot = ptypeCount + lac;
+ slotToArgTab = new int[slot+1];
-+ argToSlotTab = new int[ptypeCount];
++ argToSlotTab = new int[1+ptypeCount];
++ argToSlotTab[0] = slot; // argument "-1" is past end of slots
+ for (int i = 0; i < epts.length; i++) {
+ Class<?> pt = epts[i];
+ if (hasTwoArgSlots(pt)) --slot;
+ --slot;
+ slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
-+ argToSlotTab[i] = slot;
++ argToSlotTab[1+i] = slot;
+ }
+ assert(slot == 0); // filled the table
+ }
@@ -1567,11 +3938,12 @@ new file mode 100644
+ if (slotToArgTab == null) {
+ int slot = ptypeCount; // first arg is deepest in stack
+ slotToArgTab = new int[slot+1];
-+ argToSlotTab = new int[ptypeCount];
++ argToSlotTab = new int[1+ptypeCount];
++ argToSlotTab[0] = slot; // argument "-1" is past end of slots
+ for (int i = 0; i < ptypeCount; i++) {
+ --slot;
+ slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
-+ argToSlotTab[i] = slot;
++ argToSlotTab[1+i] = slot;
+ }
+ }
+ this.argToSlotTable = argToSlotTab;
@@ -1579,8 +3951,8 @@ new file mode 100644
+
+ if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments");
+
-+ // Allow lower layer to initialize other derived information.
-+ super.init(erase, parameterSlotCount());
++ // send a few bits down to the JVM:
++ this.vmslots = parameterSlotCount();
+ }
+
+ private static boolean hasTwoArgSlots(Class<?> type) {
@@ -1603,10 +3975,10 @@ new file mode 100644
+ };
+ // used only for making FAKE[]:
+ private MethodTypeForm(boolean varargs) {
-+ super(TOKEN);
+ this.varargs = varargs;
+ primCounts = argCounts = -1;
-+ erase = wrap = null;
++ erasedType = wrappedType = null;
++ vmslots = -1;
+ argToSlotTable = slotToArgTable = null;
+ }
+
@@ -1635,7 +4007,7 @@ new file mode 100644
+ return unpack(primCounts, 0);
+ }
+ public int parameterToArgSlot(int i) {
-+ return argToSlotTable[i];
++ return argToSlotTable[1+i];
+ }
+ public int argSlotToParameter(int argSlot) {
+ // Note: Empty slots are represented by zero in this table.
@@ -1721,169 +4093,6 @@ new file mode 100644
+ 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,158 @@
-+/*
-+ * 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<?> type) {
-+ if (!type.isPrimitive()) {
-+ return type;
-+ }
-+ if (wrappers.isEmpty()) {
-+ fillWrappers();
-+ }
-+ Object[] memo = wrappers.get(type);
-+ assert (memo != null);
-+ return (Class<?>) memo[0];
-+ }
-+
-+ public static Class<?> asPrimitiveType(Class<?> type) {
-+ if (type.isPrimitive()) {
-+ return type;
-+ }
-+ if (wrappers.isEmpty()) {
-+ fillWrappers();
-+ }
-+ Object[] memo = wrappers.get(type);
-+ if (memo == null) {
-+ return type;
-+ }
-+ return (Class<?>) memo[1];
-+ }
-+
-+ public static char basicTypeChar(Class<?> type) {
-+ if (!type.isPrimitive()) {
-+ return 'L';
-+ }
-+ if (wrappers.isEmpty()) {
-+ fillWrappers();
-+ }
-+ Object[] memo = wrappers.get(type);
-+ assert (memo != null);
-+ return (char) (Character) memo[2];
-+ }
-+
-+ static final String PRIMITIVE_BITS_TABLE = "ZBCSFI DJ";
-+ // "-012345678"
-+
-+ /** Return the number of bits in the given type, or zero for refs. */
-+ public static int bitWidth(Class<?> type) {
-+ return bitWidth(basicTypeChar(type));
-+ }
-+
-+ /** Return the number of bits in the given basic type, or zero for refs. */
-+ public static int bitWidth(char c) {
-+ int i = PRIMITIVE_BITS_TABLE.indexOf(c);
-+ assert(c != ' ' && (i >= 0 || c == 'L'));
-+ return i + (i & 1);
-+ }
-+
-+ /** Return the number of bits in the given type, or zero for refs. */
-+ public static boolean isSigned(Class<?> type) {
-+ return isSigned(basicTypeChar(type));
-+ }
-+
-+ /** Return the number of bits in the given basic type, or zero for refs. */
-+ public static boolean isSigned(char c) {
-+ int i = PRIMITIVE_BITS_TABLE.indexOf(c);
-+ assert(c != ' ' && (i >= 0 || c == 'L'));
-+ return (i & 1) == 0;
-+ }
-+
-+ /** Report if the type is one of int, boolean, byte, char, or short. */
-+ public static boolean isSubwordOrInt(Class<?> type) {
-+ return isSubwordOrInt(basicTypeChar(type));
-+ }
-+
-+ /** Report if the type char is one of "IZBCS". */
-+ public static boolean isSubwordOrInt(char c) {
-+ return "IZBCS".indexOf(c) >= 0;
-+ }
-+
-+ 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<?> type) {
-+ if (!type.isPrimitive()) {
-+ return null;
-+ }
-+ if (wrappers.isEmpty()) {
-+ fillWrappers();
-+ }
-+ Object[] memo = wrappers.get(type);
-+ 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
@@ -1929,7 +4138,7 @@ new file mode 100644
+ * of the type mismatch, at method handle construction time,
+ * instead of when the mismatched method handle is called.
+ *
-+ * @author jrose
++ * @author John Rose, JSR 292 EG
+ */
+public class WrongMethodTypeException extends RuntimeException {
+ /**
@@ -1940,7 +4149,7 @@ new file mode 100644
+ }
+
+ /**
-+ * Constructs a {@code WrongMethodTypeException>}with the specified
++ * Constructs a {@code WrongMethodTypeException} with the specified
+ * detail message.
+ *
+ * @param s the detail message.
@@ -1949,11 +4158,11 @@ new file mode 100644
+ super(s);
+ }
+}
-diff --git a/src/share/classes/java/dyn/impl/AMH.java b/src/share/classes/java/dyn/impl/AMH.java
+diff --git a/src/share/classes/java/dyn/impl/DynCallSite.java b/src/share/classes/java/dyn/impl/DynCallSite.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/java/dyn/impl/AMH.java
-@@ -0,0 +1,356 @@
++++ b/src/share/classes/java/dyn/impl/DynCallSite.java
+@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1982,1478 +4191,72 @@ new file mode 100644
+package java.dyn.impl;
+
+import java.dyn.*;
-+import java.util.List;
+
+/**
-+ * This method handle performs simple conversion or checking of a single argument.
++ * The CallSite privately created by the JVM at every invokedynamic instruction.
+ * @author jrose
+ */
-+public class AMH extends MethodHandle {
-+
-+ /** MH to call when the the selected argument is converted. */
-+ final MethodHandle target;
++class DynCallSite extends CallSite {
++ // Fields used only by the JVM. Do not use or change.
++ Object vmref;
++ long vmdata;
+
-+ private AMH(MethodHandle target, MethodType newType,
-+ int argSlot, int conversion, Object ref) {
-+ super(Access.TOKEN, newType);
-+ this.target = target;
-+ MH.init(this, argSlot, conversion, ref);
-+ checkHandler();
-+ }
-+
-+ // TO DO: When adapting a DMH, use direct retyping if possible
-+
-+ /** Create a JVM-level adapter which will call the target MH after
-+ * possibly narrowing, casting, or dropping arguments.
-+ * @param target the target to invoke after arguments are adjusted
-+ * @param adapterType the method type of the desired result
-+ * @param dropArguments args to drop; >0 means final, <0 means initial
-+ * @return an AMH which does the job
-+ * @throws WrongMethodTypeException if the conversions are too complex
-+ */
-+ static MethodHandle buildAdapter(MethodHandle target,
-+ MethodType newType,
-+ int dropArguments) {
-+ MethodType oldType = target.type();
-+ if (oldType == newType && dropArguments == 0)
-+ return target; // well, that was easy
-+
-+ // Check return type. (Not much can be done with it.)
-+ Class<?> src = oldType.returnType();
-+ Class<?> dest = newType.returnType();
-+ int pass = MH.canPassUnchecked(src, dest);
-+ if (pass <= 0)
-+ throw new WrongMethodTypeException(newType+": cannot return unchecked value from "+target);
-+
-+ MethodType midType;
-+ int nargs = newType.parameterCount();
-+ int dropConv = RETYPE_ONLY, dropSlots = 0;
-+ MethodType dropConvType = null;
-+
-+ int ignoreNewArgs = nargs - oldType.parameterCount();
-+ if (ignoreNewArgs != 0) {
-+ if (ignoreNewArgs < 0)
-+ throw new WrongMethodTypeException(newType+": not enough arguments for target "+target);
-+
-+ List<Class<?>> argList = newType.parameterList();
-+ if (dropArguments == -ignoreNewArgs) {
-+ // It's OK for the target to ignore some arguments.
-+ // Because of the way the JVM stack grows, an adapter can
-+ // trivially ignore an initial sequence of arguments.
-+ argList = argList.subList(ignoreNewArgs, argList.size());
-+ dropConv = DROP_INITIAL;
-+ } else if (dropArguments == ignoreNewArgs) {
-+
-+ // Create a stack-cutter adapter now, to remove trailing args.
-+ argList = argList.subList(0, argList.size()-ignoreNewArgs);
-+ dropConv = DROP_FINAL;
-+ } else {
-+
-+ throw new WrongMethodTypeException(newType+": cannot drop #"+dropArguments+" to match "+target);
-+ }
-+ midType = MethodType.make(newType.returnType(), argList);
-+ dropSlots = MethodTypeForm.of(midType).parameterSlotCount()
-+ - MethodTypeForm.of(newType).parameterSlotCount();
-+ assert(dropSlots >= ignoreNewArgs);
-+ assert(dropSlots <= ignoreNewArgs + MethodTypeForm.of(newType).longPrimitiveParameterCount());
-+ newType = midType;
-+ nargs = newType.parameterCount();
-+ }
-+ assert(nargs == oldType.parameterCount());
-+
-+ // work backwards through the argument pairs...
-+ int sawLongs = 0;
-+ for (int i = nargs; --i >= 0; ) {
-+ src = newType.parameterType(i);
-+ dest = oldType.parameterType(i);
-+ pass = MH.canPassUnchecked(src, dest);
-+ if (pass == 0)
-+ throw new WrongMethodTypeException(newType+": cannot convert arg #"+i+" for target "+target);
-+ if (dest == long.class || dest == double.class)
-+ ++sawLongs;
-+ if (pass > 0) continue;
-+ // need a conversion at this point
-+ if (!dest.isPrimitive()) {
-+ midType = oldType.newParameterType(i, src);
-+ target = makeCheckCast(target, midType, i + sawLongs, dest);
-+ oldType = midType;
-+ } else if (dest == boolean.class) {
-+ midType = oldType.newParameterType(i, src);
-+ target = makeTestBoolean(target, midType, i + sawLongs);
-+ oldType = midType;
-+ } else if (Wrappers.isSubwordOrInt(src)
-+ && Wrappers.isSubwordOrInt(dest)) {
-+ midType = oldType.newParameterType(i, src);
-+ target = makeExtendInt(target, midType, i + sawLongs,
-+ Wrappers.isSigned(dest), Wrappers.bitWidth(dest));
-+ oldType = midType;
-+ }
-+ }
-+
-+ // No more explicit conversions needed.
-+ // Finish with a dropping and/or retyping AMH.
-+ switch (dropConv) {
-+ case DROP_FINAL:
-+ case DROP_INITIAL:
-+ newType = dropConvType;
-+ target = makeDropArguments(target, newType, dropSlots, (dropConv == DROP_FINAL));
-+ break;
-+ default:
-+ assert(dropConv == RETYPE_ONLY);
-+ break;
-+ }
-+ if (target.type() == newType)
-+ return target;
++ private DynCallSite(Class<?> caller, String name, MethodType type) {
++ super(caller, name, type);
++ }
++
++ @Override
++ public void setTarget(MethodHandle mh) {
++ checkTarget(mh);
++ if (MH.JVM_SUPPORT)
++ MH.linkCallSite(this, mh);
+ else
-+ return makeRetypeOnly(target, newType);
-+ }
-+
-+ /** Conversions recognized by the JVM.
-+ * They must align with enum AdapterKind in vm/prims/methodHandles.hpp.
-+ */
-+ static final int
-+ RETYPE_ONLY = 0x0, // no argument changes; straight retype
-+ DROP_INITIAL = 0x1, // drop initial argument (actually a no-op)
-+ DROP_FINAL = 0x2, // drops the indicated & subsequent arguments
-+ CHECK_CAST = 0x3, // requires a klassOop parameter
-+ EXTEND_SIGN = 0x4, // includes bit-length parameter in low byte
-+ EXTEND_ZERO = 0x5, // includes bit-length parameter in low byte
-+ TEST_BOOLEAN = 0x6, // replace non-zero int value with 0x01
-+ SWAP_ARGUMENT = 0x7, // swap the last argument with indicated one
-+ PUSH_ARGUMENT = 0x8, // swap the last argument with indicated one
-+ PUSH_PRIMITIVE = 0x9, // push constant I/J/F/D value (trailing arg)
-+ PUSH_REFERENCE = 0xA, // push constant reference (trailing arg)
-+ RICOCHET = 0xB, // run an adapter chain on the return value
-+ FLYBY = 0xC, // operate first on reified argument list
-+ CONV_MASK = 0xFF; // second LSB is the conversion op field
-+
-+ @Override
-+ public String toString() {
-+ MethodType adaptedType = ((MethodHandle)this).type();
-+ Object namh = nonAdapter(target);
-+ if (namh == null) namh = "unknown";
-+ return "Adapted[" + adaptedType + "," + namh + "]";
-+ }
-+
-+ private static MethodHandle nonAdapter(MethodHandle mh) {
-+ while (mh instanceof AMH) {
-+ mh = ((AMH)mh).target;
-+ }
-+ return mh;
-+ }
-+
-+ /* Return one plus the position of the sole non-trivial difference
-+ * between the given types. This is not a symmetric operation;
-+ * we are considering adapting the targetType to adapterType.
-+ * Trivial differences are those which could be ignored by the JVM
-+ * without subverting the verifier.
-+ * Return zero if there are no non-trivial differences.
-+ * Otherwise, return the -2-N where N is the first non-trivial
-+ * argument difference, or -1 for some other difference.
-+ */
-+ private static int diffTypes(MethodType targetType,
-+ MethodType adapterType) {
-+ Class<?> src = targetType.returnType();
-+ Class<?> dest = adapterType.returnType();
-+ if (MH.canPassUnchecked(src, dest) <= 0)
-+ return -1;
-+ int nargs = adapterType.parameterCount();
-+ if (nargs != targetType.parameterCount())
-+ return -1;
-+ return diffTypes(targetType, 0, adapterType, 0, nargs);
-+ }
-+ private static int diffTypes(MethodType targetType, int tstart,
-+ MethodType adapterType, int astart,
-+ int nargs) {
-+ int res = 0;
-+ for (int i = 0; i < nargs; i++) {
-+ Class<?> src = adapterType.parameterType(tstart+i);
-+ Class<?> dest = targetType.parameterType(astart+i);
-+ if (MH.canPassUnchecked(src, dest) <= 0) {
-+ // found a difference; is it the only one so far?
-+ if (res != 0)
-+ return -1-res; // return -2-i for prev. i
-+ res = 1+i;
-+ }
-+ }
-+ return res;
-+ }
-+
-+ /** Can a retyping adapter (alone) validly convert target to newType? */
-+ static boolean canRetypeOnly(MethodHandle target, MethodType newType) {
-+ return diffTypes(target.type(), newType) == 0;
-+ }
-+
-+ /** Factory method: Performs no conversions; simply retypes the target. */
-+ static MethodHandle makeRetypeOnly(MethodHandle target, MethodType newType) {
-+ assert(canRetypeOnly(target, newType));
-+ return new AMH(target, newType, 0, RETYPE_ONLY, null);
-+ }
-+
-+ /** Can an adapter simply drop arguments to convert target to newType? */
-+ static boolean canDropArguments(MethodHandle target, MethodType newType,
-+ int dropArgs, boolean dropAfter) {
-+ MethodType oldType = target.type();
-+ List<Class<?>> ptypes = oldType.parameterList();
-+ if (dropArgs > ptypes.size())
-+ return false;
-+ if (dropAfter)
-+ ptypes = ptypes.subList(0, ptypes.size() - dropArgs);
-+ else
-+ ptypes = ptypes.subList(dropArgs, ptypes.size());
-+ MethodType midType = MethodType.make(oldType.returnType(), ptypes);
-+ return diffTypes(midType, newType) == 0;
-+ }
-+
-+ /** Factory method: Drop selected initial or final arguments. */
-+ static MethodHandle makeDropArguments(MethodHandle target, MethodType newType,
-+ int dropArgs, boolean dropAfter) {
-+ assert(canDropArguments(target, newType, dropArgs, dropAfter));
-+ int dropSlots, conv;
-+ MethodTypeForm form = MethodTypeForm.of(target.type());
-+ int argCount = form.parameterCount();
-+ int slotCount = form.parameterSlotCount();
-+ if (dropArgs == 0) {
-+ conv = RETYPE_ONLY;
-+ dropSlots = 0;
-+ } else if (dropArgs == argCount) {
-+ conv = DROP_INITIAL; // could choose either...
-+ dropSlots = slotCount;
-+ } else if (dropAfter) {
-+ conv = DROP_FINAL;
-+ int lastKeptArg = argCount - dropArgs - 1;
-+ // pop to last kept arg:
-+ dropSlots = form.parameterToArgSlot(lastKeptArg);
-+ assert(dropSlots > 0 && dropSlots < slotCount);
-+ } else {
-+ conv = DROP_INITIAL;
-+ int lastDroppedArg = dropArgs - 1;
-+ dropSlots = slotCount - form.parameterToArgSlot(lastDroppedArg);
-+ assert(dropSlots > 0 && dropSlots < slotCount);
-+ }
-+ return new AMH(target, newType, dropSlots, conv, null);
-+ }
-+
-+ /** Can a checkcast adapter validly convert target to newType? */
-+ static boolean canCheckCast(MethodHandle target, MethodType newType,
-+ int arg, Class<?> destClass) {
-+ MethodType targetType = target.type();
-+ int pass = MH.canPassUnchecked(destClass, targetType.parameterType(arg));
-+ if (pass <= 0)
-+ return false;
-+ pass = MH.canPassUnchecked(newType.parameterType(arg), destClass);
-+ if (pass >= 0)
-+ return (pass != 0);
-+ int diff = diffTypes(target.type(), newType);
-+ // allow any cast between reference types, even a silly one
-+ return (diff == 0 || diff == arg+1);
-+ }
-+
-+ /** Factory method: Forces a cast at the given argument. */
-+ static MethodHandle makeCheckCast(MethodHandle target, MethodType newType,
-+ int arg, Class<?> destClass) {
-+ assert(canCheckCast(target, newType, arg, destClass));
-+ int argSlot = MethodTypeForm.of(newType).parameterToArgSlot(arg);
-+ return new AMH(target, newType, argSlot, CHECK_CAST, destClass);
-+ }
-+
-+ /** Can an integer truncation adapter validly convert target to newType? */
-+ static boolean canExtendInt(MethodHandle target, MethodType newType,
-+ int arg, boolean signed, int bitWidth) {
-+ if (arg >= newType.parameterCount())
-+ return false;
-+ if (bitWidth >= 32 || bitWidth <= 0)
-+ throw new IllegalArgumentException("bitWidth="+bitWidth);
-+ MethodType oldType = target.type();
-+ int diff = diffTypes(oldType, newType);
-+ if (diff != 0 && diff != arg+1)
-+ return false;
-+ Class<?> src = oldType.parameterType(arg);
-+ Class<?> dest = newType.parameterType(arg);
-+ if (!Wrappers.isSubwordOrInt(src) || !Wrappers.isSubwordOrInt(dest))
-+ return false;
-+ // TO DO: model the conversion better, to allow more cases
-+ return signed == Wrappers.isSigned(dest) &&
-+ bitWidth <= Wrappers.bitWidth(dest);
-+ }
-+
-+ /** Factory method: Truncate the given argument with zero or sign extension. */
-+ static MethodHandle makeExtendInt(MethodHandle target, MethodType newType,
-+ int arg, boolean isSigned, int bitWidth) {
-+ assert(canExtendInt(target, newType, arg, isSigned, bitWidth));
-+ bitWidth <<= 8; // optional argument gets shifted up
-+ assert((CONV_MASK & 0xFF00) == 0); // low bits clear for bitWidth
-+ assert((bitWidth & ~0xFF00) == 0); // high bits clear for conversion op
-+ int conv = (isSigned ? EXTEND_SIGN : EXTEND_ZERO) | bitWidth;
-+ int argSlot = MethodTypeForm.of(newType).parameterToArgSlot(arg);
-+ return new AMH(target, newType, argSlot, conv, null);
-+ }
-+
-+ /** Factory method: Convert the given argument to a boolean. */
-+ private static boolean canTestBoolean(MethodHandle target, MethodType newType,
-+ int arg) {
-+ if (arg >= newType.parameterCount())
-+ return false;
-+ MethodType oldType = target.type();
-+ if (diffTypes(oldType, newType) != arg+1)
-+ return false;
-+ if (newType.parameterType(arg) != boolean.class)
-+ return false;
-+ return Wrappers.isSubwordOrInt(oldType.parameterType(arg));
-+ }
-+
-+ /** Can a boolean test adapter validly convert target to newType? */
-+ private static MethodHandle makeTestBoolean(MethodHandle target, MethodType newType, int arg) {
-+ assert(canTestBoolean(target, newType, arg));
-+ int argSlot = MethodTypeForm.of(newType).parameterToArgSlot(arg);
-+ return new AMH(target, newType, argSlot, TEST_BOOLEAN, null);
-+ }
-+
++ super.setTarget(mh);
++ }
++
++ // this is the up-call from the JVM:
++ static DynCallSite makeSite(Class<?> caller, String name, MethodType type,
++ long vmdata) {
++ DynCallSite site = new DynCallSite(caller, name, type);
++ site.vmdata = vmdata;
++ System.out.println("DynCallSite: "+site);
++ return site;
++ }
+}
-diff --git a/src/share/classes/java/dyn/impl/Access.java b/src/share/classes/java/dyn/impl/Access.java
+diff --git a/src/share/classes/java/dyn/package-info.java b/src/share/classes/java/dyn/package-info.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/java/dyn/impl/Access.java
-@@ -0,0 +1,93 @@
++++ b/src/share/classes/java/dyn/package-info.java
+@@ -0,0 +1,32 @@
+/*
+ * 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
++ * This package contains dynamic language support provided directly by
++ * the Java core class libraries and virtual machine.
++ * @author John Rose, JSR 292 EG
+ */
+
-+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,65 @@
-+/*
-+ * 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();
-+ // FIXME: The JVM should have done this:
-+ MethodTypeForm form = MethodTypeForm.of(type());
-+ int argSlot = form.parameterSlotCount();
-+ MH.setVMDataArgSlot(this, argSlot);
-+ }
-+
-+ /** 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);
-+ }
-+
-+ @Override
-+ public String toString() {
-+ return "Bound[" + super.toString() + "]";
-+ }
-+}
-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,251 @@
-+/*
-+ * 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 a 2 ints 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();
-+ }
-+
-+ /**
-+ * Determine if the JVM verifier allows a value of type src to be
-+ * passed to a formal parameter (or return variable) of type dest.
-+ * Returns 1 if the verifier allows the types to match without conversion.
-+ * Returns -1 if a cast or narrowing conversion can match the types.
-+ * (Autoboxing is not supported here; it must be done via Java code.)
-+ * Returns 0 otherwise.
-+ */
-+ static int canPassUnchecked(Class<?> src, Class<?> dest) {
-+ if (src == dest)
-+ return 1;
-+
-+ if (dest.isPrimitive()) {
-+ if (dest == void.class)
-+ // Return anything to a caller expecting void.
-+ return 1;
-+ if (!src.isPrimitive())
-+ // Cannot pass a reference to any primitive type (exc. void).
-+ return 0;
-+ boolean swt = Wrappers.isSubwordOrInt(src);
-+ boolean dwt = Wrappers.isSubwordOrInt(dest);
-+ if (swt && dwt) {
-+ if (Wrappers.bitWidth(src) >= Wrappers.bitWidth(dest))
-+ return -1; // truncation may be required
-+ if (!Wrappers.isSigned(dest) && Wrappers.isSigned(src))
-+ return -1; // sign elimination may be required
-+ return 1;
-+ }
-+ return 0;
-+
-+ } else if (src.isPrimitive()) {
-+ // Cannot pass a primitive to any reference type.
-+ // (Maybe allow null.class?)
-+ return 0;
-+ }
-+
-+ // The verifier treats interfaces exactly like Object.
-+ if (dest.isInterface()) dest = Object.class;
-+ //if (src.isInterface()) src = Object.class;
-+ if (dest == Object.class)
-+ // pass any reference to object or an arb. interface
-+ return 1;
-+ // else it's a definite "maybe" (cast is required)
-+ return -1;
-+ }
-+
-+ @Override
-+ public String toString() {
-+ String name = JVM_SUPPORT ? getMethodName(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, int argSlot, int conversion, Object ref);
-+ /** 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);
-+
-+ /** Fetch the name of the handled method, if available.
-+ * This routine is for debugging and reflection.
-+ */
-+ static native String getMethodName(MH self);
-+
-+ /** Tell the JVM that we need to change the target of an invokedynamic. */
-+ static native void linkCallSite(DynCallSite site, MH target);
-+
-+ /** Fetch the vmref field.
-+ * It will be sanitized as necessary to avoid exposing non-Java references.
-+ * This routine is for debugging and reflection.
-+ */
-+ static native Object getVMRef(MH self);
-+
-+ /** Hack the vmData field, knowing that it is of the form [index | argslot].
-+ * Leave index alone, set argslot to refer to the Nth argument.
-+ * The JVM should do this, not the Java code, because vmdata is JVM-private.
-+ */
-+ static void setVMDataArgSlot(MH self, int argSlot) {
-+ long index = self.vmdata >> 32;
-+ self.vmdata = (index << 32) | (argSlot << 32 >>> 32);
-+ }
-+
-+ 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,330 @@
-+/*
-+ * 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_LI(MethodHandle mh, int 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_LI(int 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 LI extends MethodHandleInvoker {
-+ static final int FINGERPRINT = fL | fI<<fA0;
-+ public LI(MethodType type) { super(type); }
-+ @Override public Object invoke_LI(MethodHandle mh, int a0) {
-+ checkType(mh);
-+ return ((FakeMethodHandle)mh).fake_invoke_LI(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 LI.FINGERPRINT: template = LI.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);
-+ }
-+