meth: move source files to JDK
authorjrose
Thu Jan 29 13:54:01 2009 -0800 (9 months ago)
changeset 15d6ba74ad1000
parent 144dab500eb86f
child 161ee47858109c
meth: move source files to JDK
meth.patch
series
--- a/meth.patch Thu Jan 29 13:53:27 2009 -0800
+++ b/meth.patch Thu Jan 29 13:54:01 2009 -0800
@@ -4,7 +4,7 @@ new file mode 100644
+++ b/src/share/classes/impl/java/dyn/Access.java
@@ -0,0 +1,93 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,7 @@ new file mode 100644
+ * members of this package.
+ */
+ static private final String[] FRIENDS = {
-+ "java.dyn."
++ "java.dyn.", "impl.java.dyn."
+ };
+
+ /**
@@ -100,9 +100,9 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/impl/java/dyn/AdapterMethodHandle.java
-@@ -0,0 +1,427 @@
+@@ -0,0 +1,541 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -128,10 +128,14 @@ new file mode 100644
+
+package impl.java.dyn;
+
++import impl.java.dyn.util.VerifyType;
+import impl.java.dyn.util.Wrappers;
+import java.dyn.*;
+import java.util.ArrayList;
++import java.util.Arrays;
+import java.util.List;
++import static impl.java.dyn.MethodHandleNatives.Constants.*;
++import static impl.java.dyn.MethodHandleImpl.newIllegalArgumentException;
+
+/**
+ * This method handle performs simple conversion or checking of a single argument.
@@ -148,9 +152,9 @@ new file mode 100644
+ long conv, Object convArg) {
+ super(newType, convArg, newType.parameterSlot(convArgPos(conv)));
+ this.conversion = convCode(conv);
-+ if (MethodHandle.JVM_SUPPORT) {
++ if (MethodHandleNatives.JVM_SUPPORT) {
+ // JVM might update VM-specific bits of conversion (ignore)
-+ MethodHandleImpl.init(this, target, convArgPos(conv));
++ MethodHandleNatives.init(this, target, convArgPos(conv));
+ }
+ }
+ private AdapterMethodHandle(MethodHandle target, MethodType newType,
@@ -158,140 +162,178 @@ new file mode 100644
+ 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; >0 means final, <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) {
++ private static final Access IMPL_TOKEN = Access.getToken();
++
++ // TO DO: When adapting another MH with a null conversion, clone
++ // the target and change its type, instead of adding another layer.
++
++ /**
++ * Create a JVM-level adapter method handle to conform the given method
++ * handle to the similar newType, using only pairwise argument conversions.
++ * For each argument, convert incoming argument to the exact type needed.
++ * Only null conversions are allowed on the return value (until
++ * the JVM supports ricochet adapters).
++ * The argument conversions allowed are casting, unboxing,
++ * integral widening or narrowing, and floating point widening or narrowing.
++ * @param token access check
++ * @param newType required call type
++ * @param target original method handle
++ * @return an adapter to the original handle with the desired new type,
++ * or the original target if the types are already identical
++ * @throws IllegalArgumentException if the adaptation cannot be made
++ * directly by a JVM-level adapter, without help from Java code
++ */
++ public static MethodHandle makePairwiseConversion(Access token,
++ MethodType newType, MethodHandle target) {
++ Access.check(token);
++ int len = newType.parameterCount();
+ MethodType oldType = target.type();
-+ if (oldType == newType && dropArguments == 0)
-+ return target; // well, that was easy
++ if (newType == oldType) return target;
++ if (len != oldType.parameterCount())
++ throw newIllegalArgumentException("wrong number of arguments in "+newType);
+
+ // 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();
++ Class<?> exp = newType.returnType();
++ Class<?> ret = oldType.returnType();
++ if (!VerifyType.isNullConversion(ret, exp))
++ throw newIllegalArgumentException("bad return conversion for "+newType);
++
++ // Find last non-trivial conversion.
++ int lastConv = len-1;
++ while (lastConv >= 0) {
++ Class<?> src = newType.parameterType(lastConv); // source type
++ Class<?> dst = oldType.parameterType(lastConv); // destination type
++ if (src == dst || VerifyType.isNullConversion(src, dst)) {
++ --lastConv;
+ } else {
-+ throw new WrongMethodTypeException(newType+": cannot drop #"+dropArguments+" to match "+target);
++ break;
+ }
-+ 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;
++ }
++ // Now build a chain of one or more adapters.
++ MethodHandle adapter = target;
++ MethodType midType = oldType.changeReturnType(exp);
++ for (int i = 0; i <= lastConv; i++) {
++ Class<?> src = newType.parameterType(i); // source type
++ Class<?> dst = midType.parameterType(i); // destination type
++ if (src == dst || VerifyType.isNullConversion(src, dst)) {
++ // do nothing: difference is trivial
++ continue;
+ }
-+ }
-+
-+ // 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) {
++ // Work the current type backward toward the desired caller type:
++ if (i != lastConv) {
++ midType = midType.changeParameterType(i, src);
++ } else {
++ // When doing the last (or only) real conversion,
++ // force all remaining null conversions to happen also.
++ assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
++ midType = newType;
++ }
++ // Tricky case analysis follows.
++ boolean srcPrim = src.isPrimitive();
++ boolean dstPrim = dst.isPrimitive();
++ if (!srcPrim && !dstPrim && canCheckCast(src, dst)) {
++ // Simple reference conversion.
++ // Note: Do not check for a class hierarchy relation
++ // between src and dst. In all cases a 'null' argument
++ // will pass the cast conversion.
++ adapter = makeCheckCast(token, midType, adapter, i, dst);
++ } else if (srcPrim && dstPrim && canPrimCast(src, dst)) {
++ // Convert a primitive to a primitive, if the JVM supports it.
++ adapter = makePrimCast(token, midType, adapter, i, dst);
++ } else if (!srcPrim && dstPrim && canUnboxArgument(src, dst)) {
++ // Caller has boxed a primitive. Unbox it for the target.
++ // The box type must correspond exactly to the primitive type.
++ // This is simpler than the powerful set of widening
++ // conversions supported by reflect.Method.invoke.
++ // Those conversions require a big nest of if/then/else logic,
++ // which we prefer to make a user responsibility.
++ adapter = makeUnboxArgument(token, midType, adapter, i, dst);
++ } else {
++ throw newIllegalArgumentException("bad argument #"+i+" conversion in "+newType);
++ }
++ assert(adapter.type() == midType);
++ }
++ if (adapter.type() != newType) {
++ // Only trivial conversions remain.
++ adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
++ // Actually, that's because there were no non-trivial ones:
++ assert(lastConv == -1);
++ }
++ assert(adapter.type() == newType);
++ return adapter;
++ }
++
++ /**
++ * Create a JVM-level adapter method handle to permute the arguments
++ * of the given method.
++ * @param token access check
++ * @param newType required call type
++ * @param target original method handle
++ * @param argumentMap for each target argument, position of its source in newType
++ * @return an adapter to the original handle with the desired new type,
++ * or the original target if the types are already identical
++ * and the permutation is null
++ * @throws IllegalArgumentException if the adaptation cannot be made
++ * directly by a JVM-level adapter, without help from Java code
++ */
++ public static MethodHandle makePermutation(Access token,
++ MethodType newType, MethodHandle target,
++ int[] argumentMap) {
++ MethodType oldType = target.type();
++ boolean nullPermutation = true;
++ for (int i = 0; i < argumentMap.length; i++) {
++ int pos = argumentMap[i];
++ if (pos != i)
++ nullPermutation = false;
++ if (pos < 0 || pos >= newType.parameterCount()) {
++ argumentMap = new int[0]; break;
++ }
++ }
++ if (argumentMap.length != oldType.parameterCount())
++ throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
++ if (nullPermutation)
++ return makePairwiseConversion(token, newType, target); // well, that was easy
++
++ // Check return type. (Not much can be done with it.)
++ Class<?> exp = newType.returnType();
++ Class<?> ret = oldType.returnType();
++ if (!VerifyType.isNullConversion(ret, exp))
++ throw newIllegalArgumentException("bad return conversion for "+newType);
++
++ // See if the argument types match up.
++ for (int i = 0; i < argumentMap.length; i++) {
++ int j = argumentMap[i];
++ Class<?> src = newType.parameterType(j);
++ Class<?> dst = oldType.parameterType(i);
++ if (!VerifyType.isNullConversion(src, dst))
++ throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
++ }
++
++ // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
++ // A workable greedy algorithm is as follows:
++ // Drop unused outgoing arguments (right to left: shallowest first).
++ // Duplicate doubly-used outgoing arguments (left to right: deepest first).
++ // Then the remaining problem is a true argument permutation.
++ // Marshal the outgoing arguments as required from left to right.
++ // That is, find the deepest outgoing stack position that does not yet
++ // have the correct argument value, and correct at least that position
++ // by swapping or rotating in the misplaced value (from a shallower place).
++ // If the misplaced value is followed by one or more consecutive values
++ // (also misplaced) issue a rotation which brings as many as possible
++ // into position. Otherwise make progress with either a swap or a
++ // rotation. Prefer the swap as cheaper, but do not use it if it
++ // breaks a slot pair. Prefer the rotation over the swap if it would
++ // preserve more consecutive values shallower than the target position.
++ // When more than one rotation will work (because the required value
++ // is already adjacent to the target position), then use a rotation
++ // which moves the old value in the target position adjacent to
++ // one of its consecutive values. Also, prefer shorter rotation
++ // spans, since they use fewer memory cycles for shuffling.
++
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ private static byte basicType(Class<?> type) {
+ if (type == null) return T_VOID;
+ char c = Wrappers.basicTypeChar(type);
+ switch (c) {
@@ -311,13 +353,13 @@ new file mode 100644
+ /** Number of stack slots for the given type.
+ * Two for T_DOUBLE and T_FLOAT, one for the rest.
+ */
-+ static int type2size(byte type) {
++ private static int type2size(int type) {
+ assert(type >= T_BOOLEAN && type <= T_OBJECT);
+ return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
+ }
+
+ /** Construct an adapter conversion descriptor for a single-argument conversion. */
-+ static long makeConv(short convOp, int argnum, byte src, byte dest) {
++ private static long makeConv(int convOp, int argnum, int src, int dest) {
+ assert(src == (src & 0xF));
+ assert(dest == (dest & 0xF));
+ assert(convOp == (convOp & CONV_OP_MASK));
@@ -330,7 +372,7 @@ new file mode 100644
+ stackMove << CONV_STACK_MOVE_SHIFT
+ );
+ }
-+ static long makeConv(short convOp, int argnum, int stackMove) {
++ private static long makeConv(int convOp, int argnum, int stackMove) {
+ assert(convOp == (convOp & CONV_OP_MASK));
+ assert(convOp >= SWAP_ARGS && convOp <= SPREAD_ARGS);
+ byte src = 0, dest = 0;
@@ -343,15 +385,15 @@ new file mode 100644
+ stackMove << CONV_STACK_MOVE_SHIFT
+ );
+ }
-+ static long makeConv(short convOp) {
++ private static long makeConv(int 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 (long) convOp; // stackMove, src, dst, argnum all zero
++ }
++ private static int convCode(long conv) {
+ return (int)conv;
+ }
-+ static int convArgPos(long conv) {
++ private static int convArgPos(long conv) {
+ return (int)(conv >>> 32);
+ }
+
@@ -365,7 +407,7 @@ new file mode 100644
+
+ private static MethodHandle nonAdapter(MethodHandle mh) {
+ return (MethodHandle)
-+ MethodHandleImpl.getTarget(mh, MethodHandleImpl.ETF_DIRECT_HANDLE);
++ MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE);
+ }
+
+ /* Return one plus the position of the first non-trivial difference
@@ -382,9 +424,9 @@ new file mode 100644
+ */
+ private static int diffTypes(MethodType adapterType,
+ MethodType targetType) {
-+ Class<?> src = targetType.returnType();
-+ Class<?> dest = adapterType.returnType();
-+ if (MethodHandleImpl.canPassUnchecked(src, dest) <= 0)
++ Class<?> src = targetType.returnType();
++ Class<?> dst = adapterType.returnType();
++ if (VerifyType.canPassUnchecked(src, dst) <= 0)
+ return -1;
+ int nargs = adapterType.parameterCount();
+ if (nargs != targetType.parameterCount())
@@ -401,7 +443,7 @@ new file mode 100644
+ 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) {
++ if (VerifyType.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
@@ -411,23 +453,147 @@ new file mode 100644
+ 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));
++ /** Can a retyping adapter (alone) validly convert the target to newType? */
++ public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
++ int diff = diffTypes(newType, targetType);
++ // %%% This assert is too strong. Factor diff into VerifyType and reconcile.
++ assert((diff == 0) == VerifyType.isNullConversion(newType, targetType));
++ return diff == 0;
++ }
++
++ /** Factory method: Performs no conversions; simply retypes the adapter. */
++ public static MethodHandle makeRetypeOnly(Access token,
++ MethodType newType, MethodHandle target) {
++ Access.check(token);
++ assert(canRetypeOnly(newType, target.type()));
++ // %%% TO DO: If adapter is already an adapter, fold in the retyping.
+ 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) {
++ /** Can a checkcast adapter validly convert the target to newType?
++ * The JVM supports all kind of reference casts, even silly ones.
++ */
++ public static boolean canCheckCast(MethodType newType, MethodType targetType,
++ int arg, Class<?> castType) {
++ Class<?> src = newType.parameterType(arg);
++ Class<?> dst = targetType.parameterType(arg);
++ if (!canCheckCast(src, castType)
++ || !VerifyType.isNullConversion(castType, dst))
++ return false;
++ int diff = diffTypes(newType, targetType);
++ return (diff == arg+1); // arg is sole non-trivial diff
++ }
++ /** Can an primitive conversion adapter validly convert src to dst? */
++ public static boolean canCheckCast(Class<?> src, Class<?> dst) {
++ return (!src.isPrimitive() && !dst.isPrimitive());
++ }
++
++ /** Factory method: Forces a cast at the given argument.
++ * The castType is the target of the cast, and can be any type
++ * with a null conversion to the corresponding target parameter.
++ */
++ public static MethodHandle makeCheckCast(Access token,
++ MethodType newType, MethodHandle target,
++ int arg, Class<?> castType) {
++ Access.check(token);
++ assert(canCheckCast(newType, target.type(), arg, castType));
++ long conv = makeConv(CHECK_CAST, arg, 0);
++ return new AdapterMethodHandle(target, newType, conv, castType);
++ }
++
++ /** Can an primitive conversion adapter validly convert the target to newType?
++ * The JVM currently supports all conversions except those between
++ * floating and integral types.
++ */
++ public static boolean canPrimCast(MethodType newType, MethodType targetType,
++ int arg, Class<?> convType) {
++ Class<?> src = newType.parameterType(arg);
++ Class<?> dst = targetType.parameterType(arg);
++ if (!canPrimCast(src, convType)
++ || !VerifyType.isNullConversion(convType, dst))
++ return false;
++ int diff = diffTypes(newType, targetType);
++ return (diff == arg+1); // arg is sole non-trivial diff
++ }
++ /** Can an primitive conversion adapter validly convert src to dst? */
++ public static boolean canPrimCast(Class<?> src, Class<?> dst) {
++ if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
++ return false;
++ } else if (Wrappers.isFloating(dst)) {
++ // both must be floating types
++ return Wrappers.isFloating(src);
++ } else {
++ // both are integral, and all combinations work fine
++ assert(Wrappers.isIntegral(src) && Wrappers.isIntegral(dst));
++ return true;
++ }
++ }
++
++ /** Factory method: Truncate the given argument with zero or sign extension,
++ * and/or convert between single and doubleword versions of integer or float.
++ * The convType is the target of the conversion, and can be any type
++ * with a null conversion to the corresponding target parameter.
++ */
++ public static MethodHandle makePrimCast(Access token,
++ MethodType newType, MethodHandle target,
++ int arg, Class<?> convType) {
++ Access.check(token);
+ MethodType oldType = target.type();
-+ List<Class<?>> ptypes = oldType.parameterList();
++ Class<?> src = newType.parameterType(arg);
++ Class<?> dst = oldType.parameterType(arg);
++ assert(canPrimCast(newType, oldType, arg, convType));
++ long conv = makeConv(PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
++ return new AdapterMethodHandle(target, newType, conv);
++ }
++
++ /** Can an unboxing conversion validly convert src to dst?
++ * The JVM currently supports all kinds of casting and unboxing.
++ * The convType is the unboxed type; it can be either a primitive or wrapper.
++ */
++ public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
++ int arg, Class<?> convType) {
++ Class<?> src = newType.parameterType(arg);
++ Class<?> dst = targetType.parameterType(arg);
++ Class<?> boxType = Wrappers.asWrapperType(convType);
++ convType = Wrappers.asPrimitiveType(convType);
++ if (!canCheckCast(src, boxType)
++ || boxType == convType
++ || !VerifyType.isNullConversion(convType, dst))
++ return false;
++ int diff = diffTypes(newType, targetType);
++ return (diff == arg+1); // arg is sole non-trivial diff
++ }
++ /** Can an primitive unboxing adapter validly convert src to dst? */
++ public static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
++ return (!src.isPrimitive() && Wrappers.asPrimitiveType(dst).isPrimitive());
++ }
++
++ /** Factory method: Unbox the given argument. */
++ public static MethodHandle makeUnboxArgument(Access token,
++ MethodType newType, MethodHandle target,
++ int arg, Class<?> convType) {
++ MethodType oldType = target.type();
++ Class<?> src = newType.parameterType(arg);
++ Class<?> dst = oldType.parameterType(arg);
++ Class<?> boxType = Wrappers.asWrapperType(convType);
++ Class<?> primType = Wrappers.asPrimitiveType(convType);
++ assert(canUnboxArgument(newType, oldType, arg, convType));
++ MethodType castDone = newType;
++ if (!VerifyType.isNullConversion(src, boxType))
++ castDone = newType.changeParameterType(arg, boxType);
++ long conv = makeConv(REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
++ MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
++ if (castDone == newType)
++ return adapter;
++ return makeCheckCast(token, newType, adapter, arg, boxType);
++ }
++
++ // TO DO: makeBoxArgument, makeSwapArguments, makeRotateArguments, makeDuplicateArguments
++
++ /** Can an adapter simply drop arguments to convert the target to newType? */
++ public static boolean canDropArguments(MethodType newType, MethodType targetType,
++ int dropArgPos, int dropArgCount) {
++ List<Class<?>> ptypes = targetType.parameterList();
+ int nptypes = ptypes.size();
+ if ((dropArgPos | dropArgCount) < 0)
+ return false;
@@ -442,20 +608,21 @@ new file mode 100644
+ ptypes = new ArrayList<Class<?>>(ptypes);
+ ptypes.subList(dropArgPos, dropArgPos + dropArgCount).clear();
+ }
-+ MethodType midType = MethodType.make(oldType.returnType(), ptypes);
++ MethodType midType = MethodType.make(targetType.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));
++ public static MethodHandle makeDropArguments(Access token,
++ MethodType newType, MethodHandle target,
++ int dropArgPos, int dropArgCount) {
++ Access.check(token);
++ assert(canDropArguments(newType, target.type(), dropArgPos, dropArgCount));
+ MethodType mt = target.type();
+ int argCount = mt.parameterCount();
+ int dropSlotCount, dropSlotPos;
+ if (dropArgCount <= 0) {
-+ return makeRetypeOnly(newType, target);
++ return makeRetypeOnly(IMPL_TOKEN, newType, target);
+ } else if (dropArgCount >= argCount) {
+ assert(dropArgPos == argCount-1);
+ dropSlotPos = 0;
@@ -473,60 +640,7 @@ new file mode 100644
+ 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);
-+ }
++ // TO DO: makeCollectArguments, makeSpreadArguments, makeFlyby, makeRicochet
+}
diff --git a/src/share/classes/impl/java/dyn/BoundMethodHandle.java b/src/share/classes/impl/java/dyn/BoundMethodHandle.java
new file mode 100644
@@ -534,7 +648,7 @@ new file mode 100644
+++ b/src/share/classes/impl/java/dyn/BoundMethodHandle.java
@@ -0,0 +1,88 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -583,9 +697,9 @@ new file mode 100644
+ // check the type now, once for all:
+ this.argument = mh.type().parameterType(0).cast(argument);
+ this.vmargslot = this.type().parameterSlotCount();
-+ if (MethodHandle.JVM_SUPPORT) {
++ if (MethodHandleNatives.JVM_SUPPORT) {
+ this.vmtarget = null; // maybe updated by JVM
-+ MethodHandleImpl.init(this, mh, 0);
++ MethodHandleNatives.init(this, mh, 0);
+ } else {
+ this.vmtarget = mh;
+ }
@@ -599,9 +713,9 @@ new file mode 100644
+ 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) {
++ if (MethodHandleNatives.JVM_SUPPORT) {
+ this.vmtarget = null; // maybe updated by JVM
-+ MethodHandleImpl.init(this, mh, argnum);
++ MethodHandleNatives.init(this, mh, argnum);
+ } else {
+ this.vmtarget = mh;
+ }
@@ -627,7 +741,7 @@ new file mode 100644
+++ b/src/share/classes/impl/java/dyn/CallSiteImpl.java
@@ -0,0 +1,60 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -671,8 +785,8 @@ new file mode 100644
+ @Override
+ public void setTarget(MethodHandle mh) {
+ checkTarget(mh);
-+ if (MethodHandleImpl.JVM_SUPPORT)
-+ MethodHandleImpl.linkCallSite(this, (MethodHandleImpl) mh);
++ if (MethodHandleNatives.JVM_SUPPORT)
++ MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
+ else
+ super.setTarget(mh);
+ }
@@ -690,9 +804,9 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/impl/java/dyn/DirectMethodHandle.java
-@@ -0,0 +1,65 @@
+@@ -0,0 +1,53 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -719,7 +833,7 @@ new file mode 100644
+package impl.java.dyn;
+
+import java.dyn.*;
-+import java.lang.reflect.Method;
++import static impl.java.dyn.MethodHandleNatives.Constants.*;
+
+/**
+ * The flavor of method handle which emulates invokespecial or invokestatic.
@@ -727,42 +841,30 @@ new file mode 100644
+ */
+class DirectMethodHandle extends MethodHandle {
+ //inherited oop vmtarget; // methodOop or virtual class/interface oop
-+ private final int vmindex; // method index within interface
++ private final int vmindex; // method index within class or interface
++ { vmindex = VM_INDEX_UNINITIALIZED; } // JVM may change this
+
+ // Constructors in this class *must* be package scoped or private.
-+ DirectMethodHandle(MethodType 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();
++ DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> caller) {
++ super(Access.TOKEN, mtype);
++
++ assert(m.isMethod() || !doDispatch && m.isConstructor());
++ if (!m.isResolved())
++ throw new InternalError();
++ MethodHandleNatives.init(this, (Object) m, doDispatch, caller);
++ }
++
++ boolean isValid() {
++ return (vmindex != VM_INDEX_UNINITIALIZED);
+ }
+}
-diff --git a/src/share/classes/impl/java/dyn/MethodHandleImpl.java b/src/share/classes/impl/java/dyn/MethodHandleImpl.java
+diff --git a/src/share/classes/impl/java/dyn/JavaMethodHandle.java b/src/share/classes/impl/java/dyn/JavaMethodHandle.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/impl/java/dyn/MethodHandleImpl.java
-@@ -0,0 +1,408 @@
++++ b/src/share/classes/impl/java/dyn/JavaMethodHandle.java
+@@ -0,0 +1,552 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -788,14 +890,1127 @@ new file mode 100644
+
+package impl.java.dyn;
+
-+import impl.java.dyn.util.MethodHandleAdapter;
-+import impl.java.dyn.util.MethodHandleInvoker;
-+import impl.java.dyn.util.Wrappers;
++import impl.java.dyn.util.*;
++import java.dyn.MethodHandle;
++import java.dyn.MethodHandles;
++import java.dyn.MethodType;
++
++/**
++ * General-purpose method handle combinator.
++ * It is invoked on an argument list, and performs whatever processing
++ * is needed, eventually returning the required return value.
++ * Note the distinctions from the low-level adapters supported directly
++ * by the JVM. Those low-level adapters perform argument conversion
++ * and delegate directly to target method handles, without executing
++ * any Java code. These Java-level adapters execute Java code to define
++ * their method handle semantics; whether they delegate to other method
++ * handles (as they often do) is a detail of that Java code.
++ * <p>
++ * If you are creating a method handle for a specific method type,
++ * do not use this class; simply use {@link MethodHandles#bind}.
++ * This class is designed for applications which must be polymorphic
++ * across a range of method types.
++ *
++ * @author jrose
++ */
++public abstract class JavaMethodHandle {
++ private final MethodType exactType;
++ private final MethodType rawType;
++ private final String rawName;
++
++ // summary of the structure of type
++ //private final int fingerprint;
++
++ /** Intended type of any method handle made from this adapter. */
++ public final MethodType type() {
++ return exactType;
++ }
++
++ /** The (exact) type of my invoke function. */
++ protected final MethodType rawType() {
++ return rawType;
++ }
++
++ /** The name of my categorical invoke function, e.g., invoke_L2. */
++ protected final String rawName() {
++ return rawName;
++ }
++
++ /**
++ * Subclasses must provide the method type which this adapter
++ * implements.
++ * @param type
++ */
++ protected JavaMethodHandle(MethodType type) {
++ this.exactType = type;
++ this.rawType = computeRawType(type);
++ this.rawName = computeRawName(type, rawType);
++ }
++
++ /** Return the type of one of my invoke functions.
++ * Can be extended by subclasses to increase the repertoire
++ * of raw invocation actions.
++ */
++ protected MethodType computeRawType(MethodType type) {
++ return categoricalMethodType(methodTypeCategory(type));
++ }
++
++ /** Return the type of one of my invoke functions.
++ * By default, of the form "invoke_$X$N" where $X is a
++ * single basic-type character (as found in bytecode signatures)
++ * and $N is the (decimal) number of parameters in the raw type.
++ * Can be extended by subclasses to increase the repertoire
++ * of raw invocation actions.
++ */
++ protected String computeRawName(MethodType exactType, MethodType rawType) {
++ char rc = Wrappers.basicTypeChar(rawType.returnType());
++ int nargs = rawType.parameterCount();
++ return "invoke_"+rc+nargs;
++ }
++
++ /** Return a permutation array which tells, for each argument
++ * to the categorical invoker, which incoming argument
++ * will supply the value (perhaps after suitable conversion).
++ * Returns null if the conversions are simply pairwise,
++ * with no reordering of argument values.
++ */
++ protected char[] computePermutation(MethodType exactType, MethodType rawType) {
++ return methodTypeCategoricalPermutation(exactType);
++ }
++
++ protected final RuntimeException illegal() {
++ return new UnsupportedOperationException();
++ }
++
++ /** Produce a method handle that binds the appropriate invoke
++ * method of this combinator.
++ * @return a method handle of this combinator's type
++ */
++ public MethodHandle handle() {
++ //return permuteAndRetypeArguments(rawHandle(), type(), computePermutation());
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ protected MethodHandle rawHandle() {
++ return MethodHandles.bind(this, rawName(), rawType());
++ }
++
++ // Pluggable behaviors, specific to particular arguments or return values.
++ protected Object res(Object x) { return exactType.returnType().cast(x); }
++ protected int res(int x) { return x; }
++ protected long res(long x) { return x; }
++
++ // A categorical method type is one which (a) avoids boxing,
++ // (b) avoids passing unused arguments, and (c) can represent
++ // the calling sequence of an original exact type.
++ //
++ // It's good to limit the number of categorical types,
++ // so that we don't have to generate too many different
++ // code shapes for Java-based adapters.
++ // We (1) erase all references to Object,
++ // (2) widen primitives to int when they fit,
++ // (3) widen other primitive arguments to long,
++ // (4) sort the argument list (refs, ints, then longs), and
++ // (5) promote ints to longs if any longs are present.
++ //
++ // Because it is harmless to ignore an int return value,
++ // if the caller is intending a void result, void can be
++ // erased to int, as with other short primitives.
++ // The distinction in return values between reference,
++ // int, long, float, and double.
++ //
++ // Therefore, the grammar of signatures is:
++ // {Object|int|long|float|double} ( Object* {int* | long*} )
++ // This gives 5(2N+1) as the number of categorical signatures
++ // of N arguments, or 5(N+1)^2 for signatures of <=N arguments.
++ // Clearly some of this needs to get code-generated lazily,
++ // but we supoprt a core set of signatures here.
++
++ protected static int category(Class<?> type) {
++ if (!type.isPrimitive()) return 0;
++ if (type == void.class) return -1;
++ if (Wrappers.bitWidth(type) > 32) return 2;
++ return 1;
++ }
++ protected static Class<?> categoricalType(int cat) {
++ switch (cat) {
++ case 0: return Object.class;
++ case 1: return int.class;
++ case 2: return long.class;
++ case 3: return void.class;
++ }
++ throw new InternalError();
++ }
++ protected static int methodTypeCategory(MethodType type) {
++ int nargs = type.parameterCount();
++ int nprims = 0;
++ int nlongs = 0;
++ for (int i = 0; i < nargs; i++) {
++ int cat = category(type.parameterType(i));
++ if (cat != 0) {
++ ++nprims;
++ if (cat == 2) ++nlongs;
++ }
++ }
++ int nrefs = nargs - nprims;
++ int nints = nprims - nlongs;
++ int rcat = category(type.returnType());
++ if (nlongs != 0) { nlongs += nints; nints = 0; } // point (5)
++ return (nlongs << 24) | (nints << 16) | (nrefs << 8) | rcat;
++ }
++ protected static char[] methodTypeCategoricalPermutation(MethodType type) {
++ return methodTypeCategoricalPermutation(type, methodTypeCategory(type));
++ }
++ protected static char[] methodTypeCategoricalPermutation(MethodType type, int category) {
++ int x = category;
++ int rcat = (x & 0xFF); x >>= 8;
++ int nrefs = (x & 0xFF); x >>= 8;
++ int nints = (x & 0xFF); x >>= 8;
++ int nlongs = (x & 0xFF); x >>= 8;
++ int nargs = type.parameterCount();
++ assert(nargs == nrefs + nints + nlongs);
++ char[] permutation = new char[nargs];
++ int nextref = 0, nextint = nrefs, nextlong = nrefs + nints;
++ int reflimit = nextint, intlimit = nextlong, longlimit = nargs;
++ boolean sawReorder = false;
++ for (int i = 0; i < nargs; i++) {
++ int cat = category(type.parameterType(i));
++ int nextarg;
++ if (cat == 0)
++ nextarg = nextref++;
++ else if (nextint == intlimit || cat == 2)
++ nextarg = nextlong++;
++ else
++ nextarg = nextint++;
++ // Next outgoing argument (to the categorical invoke method)
++ // is going to come from exactType.parameterType(i)
++ assert(permutation[nextarg] == 0);
++ permutation[nextarg] = (char) i;
++ if (nextarg != i) sawReorder = true;
++ }
++ assert(nextref == reflimit);
++ assert(nextint == intlimit);
++ assert(nextlong == longlimit);
++ if (!sawReorder) return null; // this is always a special case
++ return permutation;
++ }
++ protected static MethodType categoricalMethodType(int category) {
++ int x = category;
++ int rcat = (x & 0xFF); x >>= 8;
++ int nrefs = (x & 0xFF); x >>= 8;
++ int nints = (x & 0xFF); x >>= 8;
++ int nlongs = (x & 0xFF); x >>= 8;
++ return categoricalMethodType(rcat, nrefs, nints, nlongs);
++ }
++ protected static MethodType categoricalMethodType(int rcat, int nrefs, int nints, int nlongs) {
++ int nshorts = nints + nlongs;
++ Class<?> ptypes[] = new Class<?>[nshorts + nlongs];
++ int cat = 0;
++ Class<?> ptype = categoricalType(cat);
++ for (int i = 0; i < ptypes.length; i++) {
++ if (i == nrefs) ptype = categoricalType(++cat);
++ if (i == nshorts) ptype = categoricalType(++cat);
++ ptypes[i] = ptype;
++ }
++ Class<?> rtype = categoricalType(rcat);
++ return MethodType.make(rtype, ptypes);
++ }
++
++ // Categorical methods up to arity 5 (180 of them).
++ // They are (arbitrarily) split up in subclasses.
++ /*
++ (defun insert-categorical-methods (max-arity &optional max-rcat)
++ (let* ((types (list "Object" "int " "long " "float " "double"))
++ (tchars (list "L" "I" "J" "F" "D"))
++ invoke acat nrefs
++ (do-case (function (lambda (rcat nargs nrefs nints nlongs)
++ (setq invoke (format "invoke_%s%d" (elt tchars rcat) nargs))
++ (insert "\n protected " (elt types rcat) " " invoke "(")
++ (dotimes (arg nargs)
++ (setq acat (cond ((< arg nrefs) 0) ((< arg (+ nrefs nints)) 1) (t 2)))
++ (insert (if (= 0 arg) "" ", ") (elt types acat) (format " a%d" arg)))
++ (insert ") { throw illegal(); }")))))
++ (dotimes (rcat (1+ (or max-rcat 4))) (dotimes (nargs (1+ max-arity))
++ (setq invoke (format "%s%d" (elt tchars rcat) nargs))
++ (insert "\n static class " invoke " extends JavaMethodHandle {")
++ (insert "\n " invoke "(MethodType type) { super(type); }")
++ (funcall do-case rcat nargs nargs 0 0)
++ (dotimes (j 2) (dotimes (i nargs) (setq nrefs (- nargs i 1))
++ (if (= j 0) (funcall do-case rcat nargs nrefs (- nargs nrefs) 0)
++ (funcall do-case rcat nargs nrefs 0 (- nargs nrefs)))))
++ (insert "\n }")
++ ))))
++ */
++ // (progn (insert-categorical-methods 5 4) (insert "\n}"))
++ /*
++ static class L0 extends JavaMethodHandle {
++ L0(MethodType type) { super(type); }
++ protected Object invoke_L0() { throw illegal(); }
++ }
++ static class L1 extends JavaMethodHandle {
++ L1(MethodType type) { super(type); }
++ protected Object invoke_L1(Object a0) { throw illegal(); }
++ protected Object invoke_L1(int a0) { throw illegal(); }
++ protected Object invoke_L1(long a0) { throw illegal(); }
++ }
++ static class L2 extends JavaMethodHandle {
++ L2(MethodType type) { super(type); }
++ protected Object invoke_L2(Object a0, Object a1) { throw illegal(); }
++ protected Object invoke_L2(Object a0, int a1) { throw illegal(); }
++ protected Object invoke_L2(int a0, int a1) { throw illegal(); }
++ protected Object invoke_L2(Object a0, long a1) { throw illegal(); }
++ protected Object invoke_L2(long a0, long a1) { throw illegal(); }
++ }
++ static class L3 extends JavaMethodHandle {
++ L3(MethodType type) { super(type); }
++ protected Object invoke_L3(Object a0, Object a1, Object a2) { throw illegal(); }
++ protected Object invoke_L3(Object a0, Object a1, int a2) { throw illegal(); }
++ protected Object invoke_L3(Object a0, int a1, int a2) { throw illegal(); }
++ protected Object invoke_L3(int a0, int a1, int a2) { throw illegal(); }
++ protected Object invoke_L3(Object a0, Object a1, long a2) { throw illegal(); }
++ protected Object invoke_L3(Object a0, long a1, long a2) { throw illegal(); }
++ protected Object invoke_L3(long a0, long a1, long a2) { throw illegal(); }
++ }
++ static class L4 extends JavaMethodHandle {
++ L4(MethodType type) { super(type); }
++ protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, Object a1, Object a2, int a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, Object a1, int a2, int a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, int a1, int a2, int a3) { throw illegal(); }
++ protected Object invoke_L4(int a0, int a1, int a2, int a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, Object a1, Object a2, long a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, Object a1, long a2, long a3) { throw illegal(); }
++ protected Object invoke_L4(Object a0, long a1, long a2, long a3) { throw illegal(); }
++ protected Object invoke_L4(long a0, long a1, long a2, long a3) { throw illegal(); }
++ }
++ static class L5 extends JavaMethodHandle {
++ L5(MethodType type) { super(type); }
++ protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, int a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, Object a2, int a3, int a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, int a2, int a3, int a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected Object invoke_L5(int a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, long a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, Object a2, long a3, long a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, Object a1, long a2, long a3, long a4) { throw illegal(); }
++ protected Object invoke_L5(Object a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ protected Object invoke_L5(long a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ }
++ static class I0 extends JavaMethodHandle {
++ I0(MethodType type) { super(type); }
++ protected int invoke_I0() { throw illegal(); }
++ }
++ static class I1 extends JavaMethodHandle {
++ I1(MethodType type) { super(type); }
++ protected int invoke_I1(Object a0) { throw illegal(); }
++ protected int invoke_I1(int a0) { throw illegal(); }
++ protected int invoke_I1(long a0) { throw illegal(); }
++ }
++ static class I2 extends JavaMethodHandle {
++ I2(MethodType type) { super(type); }
++ protected int invoke_I2(Object a0, Object a1) { throw illegal(); }
++ protected int invoke_I2(Object a0, int a1) { throw illegal(); }
++ protected int invoke_I2(int a0, int a1) { throw illegal(); }
++ protected int invoke_I2(Object a0, long a1) { throw illegal(); }
++ protected int invoke_I2(long a0, long a1) { throw illegal(); }
++ }
++ static class I3 extends JavaMethodHandle {
++ I3(MethodType type) { super(type); }
++ protected int invoke_I3(Object a0, Object a1, Object a2) { throw illegal(); }
++ protected int invoke_I3(Object a0, Object a1, int a2) { throw illegal(); }
++ protected int invoke_I3(Object a0, int a1, int a2) { throw illegal(); }
++ protected int invoke_I3(int a0, int a1, int a2) { throw illegal(); }
++ protected int invoke_I3(Object a0, Object a1, long a2) { throw illegal(); }
++ protected int invoke_I3(Object a0, long a1, long a2) { throw illegal(); }
++ protected int invoke_I3(long a0, long a1, long a2) { throw illegal(); }
++ }
++ static class I4 extends JavaMethodHandle {
++ I4(MethodType type) { super(type); }
++ protected int invoke_I4(Object a0, Object a1, Object a2, Object a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, Object a1, Object a2, int a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, Object a1, int a2, int a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, int a1, int a2, int a3) { throw illegal(); }
++ protected int invoke_I4(int a0, int a1, int a2, int a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, Object a1, Object a2, long a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, Object a1, long a2, long a3) { throw illegal(); }
++ protected int invoke_I4(Object a0, long a1, long a2, long a3) { throw illegal(); }
++ protected int invoke_I4(long a0, long a1, long a2, long a3) { throw illegal(); }
++ }
++ static class I5 extends JavaMethodHandle {
++ I5(MethodType type) { super(type); }
++ protected int invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, Object a2, Object a3, int a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, Object a2, int a3, int a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, int a2, int a3, int a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected int invoke_I5(int a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, Object a2, Object a3, long a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, Object a2, long a3, long a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, Object a1, long a2, long a3, long a4) { throw illegal(); }
++ protected int invoke_I5(Object a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ protected int invoke_I5(long a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ }
++ static class J0 extends JavaMethodHandle {
++ J0(MethodType type) { super(type); }
++ protected long invoke_J0() { throw illegal(); }
++ }
++ static class J1 extends JavaMethodHandle {
++ J1(MethodType type) { super(type); }
++ protected long invoke_J1(Object a0) { throw illegal(); }
++ protected long invoke_J1(int a0) { throw illegal(); }
++ protected long invoke_J1(long a0) { throw illegal(); }
++ }
++ static class J2 extends JavaMethodHandle {
++ J2(MethodType type) { super(type); }
++ protected long invoke_J2(Object a0, Object a1) { throw illegal(); }
++ protected long invoke_J2(Object a0, int a1) { throw illegal(); }
++ protected long invoke_J2(int a0, int a1) { throw illegal(); }
++ protected long invoke_J2(Object a0, long a1) { throw illegal(); }
++ protected long invoke_J2(long a0, long a1) { throw illegal(); }
++ }
++ static class J3 extends JavaMethodHandle {
++ J3(MethodType type) { super(type); }
++ protected long invoke_J3(Object a0, Object a1, Object a2) { throw illegal(); }
++ protected long invoke_J3(Object a0, Object a1, int a2) { throw illegal(); }
++ protected long invoke_J3(Object a0, int a1, int a2) { throw illegal(); }
++ protected long invoke_J3(int a0, int a1, int a2) { throw illegal(); }
++ protected long invoke_J3(Object a0, Object a1, long a2) { throw illegal(); }
++ protected long invoke_J3(Object a0, long a1, long a2) { throw illegal(); }
++ protected long invoke_J3(long a0, long a1, long a2) { throw illegal(); }
++ }
++ static class J4 extends JavaMethodHandle {
++ J4(MethodType type) { super(type); }
++ protected long invoke_J4(Object a0, Object a1, Object a2, Object a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, Object a1, Object a2, int a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, Object a1, int a2, int a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, int a1, int a2, int a3) { throw illegal(); }
++ protected long invoke_J4(int a0, int a1, int a2, int a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, Object a1, Object a2, long a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, Object a1, long a2, long a3) { throw illegal(); }
++ protected long invoke_J4(Object a0, long a1, long a2, long a3) { throw illegal(); }
++ protected long invoke_J4(long a0, long a1, long a2, long a3) { throw illegal(); }
++ }
++ static class J5 extends JavaMethodHandle {
++ J5(MethodType type) { super(type); }
++ protected long invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, Object a2, Object a3, int a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, Object a2, int a3, int a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, int a2, int a3, int a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected long invoke_J5(int a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, Object a2, Object a3, long a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, Object a2, long a3, long a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, Object a1, long a2, long a3, long a4) { throw illegal(); }
++ protected long invoke_J5(Object a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ protected long invoke_J5(long a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ }
++ static class F0 extends JavaMethodHandle {
++ F0(MethodType type) { super(type); }
++ protected float invoke_F0() { throw illegal(); }
++ }
++ static class F1 extends JavaMethodHandle {
++ F1(MethodType type) { super(type); }
++ protected float invoke_F1(Object a0) { throw illegal(); }
++ protected float invoke_F1(int a0) { throw illegal(); }
++ protected float invoke_F1(long a0) { throw illegal(); }
++ }
++ static class F2 extends JavaMethodHandle {
++ F2(MethodType type) { super(type); }
++ protected float invoke_F2(Object a0, Object a1) { throw illegal(); }
++ protected float invoke_F2(Object a0, int a1) { throw illegal(); }
++ protected float invoke_F2(int a0, int a1) { throw illegal(); }
++ protected float invoke_F2(Object a0, long a1) { throw illegal(); }
++ protected float invoke_F2(long a0, long a1) { throw illegal(); }
++ }
++ static class F3 extends JavaMethodHandle {
++ F3(MethodType type) { super(type); }
++ protected float invoke_F3(Object a0, Object a1, Object a2) { throw illegal(); }
++ protected float invoke_F3(Object a0, Object a1, int a2) { throw illegal(); }
++ protected float invoke_F3(Object a0, int a1, int a2) { throw illegal(); }
++ protected float invoke_F3(int a0, int a1, int a2) { throw illegal(); }
++ protected float invoke_F3(Object a0, Object a1, long a2) { throw illegal(); }
++ protected float invoke_F3(Object a0, long a1, long a2) { throw illegal(); }
++ protected float invoke_F3(long a0, long a1, long a2) { throw illegal(); }
++ }
++ static class F4 extends JavaMethodHandle {
++ F4(MethodType type) { super(type); }
++ protected float invoke_F4(Object a0, Object a1, Object a2, Object a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, Object a1, Object a2, int a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, Object a1, int a2, int a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, int a1, int a2, int a3) { throw illegal(); }
++ protected float invoke_F4(int a0, int a1, int a2, int a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, Object a1, Object a2, long a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, Object a1, long a2, long a3) { throw illegal(); }
++ protected float invoke_F4(Object a0, long a1, long a2, long a3) { throw illegal(); }
++ protected float invoke_F4(long a0, long a1, long a2, long a3) { throw illegal(); }
++ }
++ static class F5 extends JavaMethodHandle {
++ F5(MethodType type) { super(type); }
++ protected float invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, Object a2, Object a3, int a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, Object a2, int a3, int a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, int a2, int a3, int a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected float invoke_F5(int a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, Object a2, Object a3, long a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, Object a2, long a3, long a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, Object a1, long a2, long a3, long a4) { throw illegal(); }
++ protected float invoke_F5(Object a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ protected float invoke_F5(long a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ }
++ static class D0 extends JavaMethodHandle {
++ D0(MethodType type) { super(type); }
++ protected double invoke_D0() { throw illegal(); }
++ }
++ static class D1 extends JavaMethodHandle {
++ D1(MethodType type) { super(type); }
++ protected double invoke_D1(Object a0) { throw illegal(); }
++ protected double invoke_D1(int a0) { throw illegal(); }
++ protected double invoke_D1(long a0) { throw illegal(); }
++ }
++ static class D2 extends JavaMethodHandle {
++ D2(MethodType type) { super(type); }
++ protected double invoke_D2(Object a0, Object a1) { throw illegal(); }
++ protected double invoke_D2(Object a0, int a1) { throw illegal(); }
++ protected double invoke_D2(int a0, int a1) { throw illegal(); }
++ protected double invoke_D2(Object a0, long a1) { throw illegal(); }
++ protected double invoke_D2(long a0, long a1) { throw illegal(); }
++ }
++ static class D3 extends JavaMethodHandle {
++ D3(MethodType type) { super(type); }
++ protected double invoke_D3(Object a0, Object a1, Object a2) { throw illegal(); }
++ protected double invoke_D3(Object a0, Object a1, int a2) { throw illegal(); }
++ protected double invoke_D3(Object a0, int a1, int a2) { throw illegal(); }
++ protected double invoke_D3(int a0, int a1, int a2) { throw illegal(); }
++ protected double invoke_D3(Object a0, Object a1, long a2) { throw illegal(); }
++ protected double invoke_D3(Object a0, long a1, long a2) { throw illegal(); }
++ protected double invoke_D3(long a0, long a1, long a2) { throw illegal(); }
++ }
++ static class D4 extends JavaMethodHandle {
++ D4(MethodType type) { super(type); }
++ protected double invoke_D4(Object a0, Object a1, Object a2, Object a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, Object a1, Object a2, int a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, Object a1, int a2, int a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, int a1, int a2, int a3) { throw illegal(); }
++ protected double invoke_D4(int a0, int a1, int a2, int a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, Object a1, Object a2, long a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, Object a1, long a2, long a3) { throw illegal(); }
++ protected double invoke_D4(Object a0, long a1, long a2, long a3) { throw illegal(); }
++ protected double invoke_D4(long a0, long a1, long a2, long a3) { throw illegal(); }
++ }
++ static class D5 extends JavaMethodHandle {
++ D5(MethodType type) { super(type); }
++ protected double invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, Object a2, Object a3, int a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, Object a2, int a3, int a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, int a2, int a3, int a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected double invoke_D5(int a0, int a1, int a2, int a3, int a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, Object a2, Object a3, long a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, Object a2, long a3, long a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, Object a1, long a2, long a3, long a4) { throw illegal(); }
++ protected double invoke_D5(Object a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ protected double invoke_D5(long a0, long a1, long a2, long a3, long a4) { throw illegal(); }
++ }
++ */
++}
+diff --git a/src/share/classes/impl/java/dyn/MemberName.java b/src/share/classes/impl/java/dyn/MemberName.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/MemberName.java
+@@ -0,0 +1,550 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn;
++
++import impl.java.dyn.util.Signatures;
+import java.dyn.*;
-+import java.lang.reflect.AccessibleObject;
++import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
++import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.Iterator;
++import java.util.List;
++import static impl.java.dyn.MethodHandleNatives.Constants.*;
++
++/**
++ * Compact information which fully characterizes a method or field reference.
++ * When resolved, it includes a direct pointer to JVM metadata.
++ * This representation is stateless and only decriptive.
++ * It provides no private information and no capability to use the member.
++ * <p>
++ * By contrast, a java.lang.reflect.Method contains fuller information
++ * about the internals of a method (except its bytecodes) and also
++ * allows invocation. A MemberName is much lighter than a reflect.Method,
++ * since it contains about 7 fields to Method's 16 (plus its sub-arrays),
++ * and those seven fields omit much of the information in Method.
++ * @author jrose
++ */
++public final class MemberName implements Member, Cloneable {
++ private Class<?> clazz; // class in which the method is defined
++ private String name; // may be null if not yet materialized
++ private Object type; // may be null if not yet materialized
++ private int flags; // modifier bits; see reflect.Modifier
++
++ private Object vmtarget; // VM-specific target value
++ private int vmindex; // method index within class or interface
++
++ { vmindex = VM_INDEX_UNINITIALIZED; }
++
++ public Class<?> getDeclaringClass() {
++ if (clazz == null && isResolved()) {
++ expandFromVM();
++ }
++ return clazz;
++ }
++
++ public ClassLoader getClassLoader() {
++ return clazz.getClassLoader();
++ }
++
++ public String getName() {
++ if (name == null) {
++ expandFromVM();
++ if (name == null) return null;
++ }
++ return name;
++ }
++
++ public MethodType getMethodType() {
++ if (type == null) {
++ expandFromVM();
++ if (type == null) return null;
++ }
++ if (!isInvocable())
++ throw newIllegalArgumentException("not invocable, no method type");
++ if (type instanceof MethodType) {
++ return (MethodType) type;
++ }
++ if (type instanceof String) {
++ String sig = (String) type;
++ MethodType res = MethodType.fromBytecodeString(sig, getClassLoader());
++ this.type = res;
++ return res;
++ }
++ if (type instanceof Object[]) {
++ Object[] typeInfo = (Object[]) type;
++ Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
++ Class<?> rtype = (Class<?>) typeInfo[0];
++ MethodType res = MethodType.make(rtype, ptypes);
++ this.type = res;
++ return res;
++ }
++ throw new InternalError("bad method type "+type);
++ }
++
++ public MethodType getInvocationType() {
++ MethodType itype = getMethodType();
++ if (!isStatic())
++ itype = itype.insertParameterType(0, clazz);
++ return itype;
++ }
++
++ public Class<?>[] getParameterTypes() {
++ return getMethodType().parameterArray();
++ }
++
++ public Class<?> getReturnType() {
++ return getMethodType().returnType();
++ }
++
++ public Class<?> getFieldType() {
++ if (type == null) {
++ expandFromVM();
++ if (type == null) return null;
++ }
++ if (isInvocable())
++ throw newIllegalArgumentException("not a field or nested class, no simple type");
++ if (type instanceof Class<?>) {
++ return (Class<?>) type;
++ }
++ if (type instanceof String) {
++ String sig = (String) type;
++ MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader());
++ Class<?> res = mtype.returnType();
++ this.type = res;
++ return res;
++ }
++ throw new InternalError("bad field type "+type);
++ }
++
++ public Object getType() {
++ return (isInvocable() ? getMethodType() : getFieldType());
++ }
++
++ public String getSignature() {
++ if (type == null) {
++ expandFromVM();
++ if (type == null) return null;
++ }
++ if (type instanceof String)
++ return (String) type;
++ if (isInvocable())
++ return Signatures.unparse(getMethodType());
++ else
++ return Signatures.unparse(getFieldType());
++ }
++
++ public int getModifiers() {
++ return (flags & RECOGNIZED_MODIFIERS);
++ }
++
++ private void setFlags(int flags) {
++ this.flags = flags;
++ assert(testAnyFlags(ALL_KINDS));
++ }
++
++ private boolean testFlags(int mask, int value) {
++ return (flags & mask) == value;
++ }
++ private boolean testAllFlags(int mask) {
++ return testFlags(mask, mask);
++ }
++ private boolean testAnyFlags(int mask) {
++ return !testFlags(mask, 0);
++ }
++
++ public boolean isStatic() {
++ return Modifier.isStatic(flags);
++ }
++ public boolean isPublic() {
++ return Modifier.isPublic(flags);
++ }
++ public boolean isPrivate() {
++ return Modifier.isPrivate(flags);
++ }
++ public boolean isProtected() {
++ return Modifier.isProtected(flags);
++ }
++ public boolean isFinal() {
++ return Modifier.isFinal(flags);
++ }
++ public boolean isAbstract() {
++ return Modifier.isAbstract(flags);
++ }
++ // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
++
++ // unofficial modifier flags, used by HotSpot:
++ static final int BRIDGE = 0x00000040;
++ static final int VARARGS = 0x00000080;
++ static final int SYNTHETIC = 0x00001000;
++ static final int ANNOTATION= 0x00002000;
++ static final int ENUM = 0x00004000;
++ public boolean isBridge() {
++ return testAllFlags(IS_METHOD | BRIDGE);
++ }
++ public boolean isVarargs() {
++ return testAllFlags(VARARGS) && isInvocable();
++ }
++ public boolean isSynthetic() {
++ return testAllFlags(SYNTHETIC);
++ }
++
++ static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
++
++ // modifiers exported by the JVM:
++ static final int RECOGNIZED_MODIFIERS = 0xFFFF;
++
++ // private flags, not part of RECOGNIZED_MODIFIERS:
++ static final int
++ IS_METHOD = MN_IS_METHOD, // method (not constructor)
++ IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
++ IS_FIELD = MN_IS_FIELD, // field
++ IS_TYPE = MN_IS_TYPE; // nested type
++ static final int // for MethodHandleNatives.getMembers
++ SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
++ SEARCH_INTERFACES = MN_SEARCH_INTERFACES;
++
++ static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
++ static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
++ static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
++ static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
++ static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
++
++ public boolean isInvocable() {
++ return testAnyFlags(IS_INVOCABLE);
++ }
++ public boolean isFieldOrMethod() {
++ return testAnyFlags(IS_FIELD_OR_METHOD);
++ }
++ public boolean isMethod() {
++ return testAllFlags(IS_METHOD);
++ }
++ public boolean isConstructor() {
++ return testAllFlags(IS_CONSTRUCTOR);
++ }
++ public boolean isField() {
++ return testAllFlags(IS_FIELD);
++ }
++ public boolean isType() {
++ return testAllFlags(IS_TYPE);
++ }
++ public boolean isPackage() {
++ return !testAnyFlags(ALL_ACCESS);
++ }
++
++ /** Initialize a query. It is not resolved. */
++ private void init(Class<?> defClass, String name, Object type, int flags) {
++ // defining class is allowed to be null (for a naked name/type pair)
++ name.toString(); // null check
++ type.equals(type); // null check
++ // fill in fields:
++ this.clazz = defClass;
++ this.name = name;
++ this.type = type;
++ setFlags(flags);
++ assert(!isResolved());
++ }
++
++ private void expandFromVM() {
++ if (!isResolved()) return;
++ if (type instanceof Object[])
++ type = null; // don't saddle JVM w/ typeInfo
++ MethodHandleNatives.expand(this);
++ }
++
++ // Capturing information from the Core Reflection API:
++ private static int flagsMods(int flags, int mods) {
++ assert((flags & RECOGNIZED_MODIFIERS) == 0);
++ assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
++ return flags | mods;
++ }
++ public MemberName(Method m) {
++ Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
++ init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
++ // fill in vmtarget, vmindex while we have m in hand:
++ MethodHandleNatives.init(this, m);
++ assert(isResolved());
++ }
++ public MemberName(Constructor ctor) {
++ Object[] typeInfo = { void.class, ctor.getParameterTypes() };
++ init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
++ // fill in vmtarget, vmindex while we have ctor in hand:
++ MethodHandleNatives.init(this, ctor);
++ assert(isResolved());
++ }
++ public MemberName(Field fld) {
++ init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
++ // fill in vmtarget, vmindex while we have fld in hand:
++ MethodHandleNatives.init(this, fld);
++ assert(isResolved());
++ }
++ public MemberName(Class<?> type) {
++ init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
++ vmindex = 0; // isResolved
++ assert(isResolved());
++ }
++
++ // bare-bones constructor; the JVM will fill it in
++ MemberName() { }
++
++ // locally useful cloner
++ @Override protected MemberName clone() {
++ try {
++ return (MemberName) super.clone();
++ } catch (CloneNotSupportedException ex) {
++ throw new InternalError();
++ }
++ }
++
++ // %%% define equals/hashcode?
++
++ // Construction from symbolic parts, for queries:
++ public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
++ init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
++ }
++ public MemberName(Class<?> defClass, String name, Class<?> type) {
++ this(defClass, name, type, 0);
++ }
++ public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
++ int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
++ init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
++ }
++ public MemberName(Class<?> defClass, String name, MethodType type) {
++ this(defClass, name, type, 0);
++ }
++
++ boolean isResolved() {
++ return (vmindex != VM_INDEX_UNINITIALIZED);
++ }
++
++ public boolean hasReceiverTypeDispatch() {
++ return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
++ }
++
++ @Override
++ public String toString() {
++ if (isType())
++ return type.toString(); // class java.lang.String
++ // else it is a field, method, or constructor
++ StringBuilder buf = new StringBuilder();
++ if (getDeclaringClass() != null) {
++ buf.append(getName(clazz));
++ buf.append('.');
++ }
++ buf.append(getName());
++ if (!isInvocable()) buf.append('/');
++ buf.append(getName(getType()));
++ /*
++ buf.append('/');
++ // key: Public, private, pRotected, sTatic, Final, sYnchronized,
++ // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
++ // (annotation), Enum, (unused)
++ final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?";
++ final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
++ String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
++ for (int i = 0; i < modChars.length(); i++) {
++ if ((flags & (1 << i)) != 0) {
++ char mc = modChars.charAt(i);
++ if (mc != '.')
++ buf.append(mc);
++ }
++ }
++ */
++ return buf.toString();
++ }
++ private static String getName(Object obj) {
++ if (obj instanceof Class<?>)
++ return ((Class<?>)obj).getName();
++ return obj.toString();
++ }
++
++ // Queries to the JVM:
++ public int getVMIndex(Access token) {
++ Access.check(token);
++ if (!isResolved())
++ throw newIllegalStateException("not resolved");
++ return vmindex;
++ }
++// public Object getVMTarget(Access token) {
++// Access.check(token);
++// if (!isResolved())
++// throw newIllegalStateException("not resolved");
++// return vmtarget;
++// }
++ private RuntimeException newIllegalStateException(String message) {
++ return new IllegalStateException(message+": "+this);
++ }
++
++ // handy shared exception makers (they simplify the common case code)
++ public static RuntimeException newIllegalArgumentException(String message) {
++ return new IllegalArgumentException(message);
++ }
++ public static NoAccessException newNoAccessException(MemberName name, Class<?> caller) {
++ return newNoAccessException("cannot access", name, caller);
++ }
++ public static NoAccessException newNoAccessException(String message,
++ MemberName name, Class<?> caller) {
++ message += ": " + name;
++ if (caller != null) message += ", from " + caller.getName();
++ return new NoAccessException(message);
++ }
++
++ /** Actually making a query requires an access check. */
++ public static Factory getFactory(Access token) {
++ Access.check(token);
++ return Factory.INSTANCE;
++ }
++ public static Factory getFactory() {
++ return getFactory(Access.getToken());
++ }
++ public static class Factory {
++ private Factory() { } // singleton pattern
++ static Factory INSTANCE = new Factory();
++
++ private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
++
++ /// Queries
++ List<MemberName> getMembers(Class<?> defc,
++ String matchName, Object matchType,
++ int matchFlags, Class<?> caller) {
++ matchFlags &= ALLOWED_FLAGS;
++ String matchSig = null;
++ if (matchType != null) {
++ matchSig = Signatures.unparse(matchType);
++ if (matchSig.startsWith("("))
++ matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
++ else
++ matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
++ }
++ final int BUF_MAX = 0x2000;
++ int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
++ MemberName[] buf = newMemberBuffer(len1);
++ int totalCount = 0;
++ ArrayList<MemberName[]> bufs = null;
++ for (;;) {
++ int bufCount = MethodHandleNatives.getMembers(defc,
++ matchName, matchSig, matchFlags, caller,
++ totalCount, buf);
++ if (bufCount <= buf.length) {
++ if (bufCount >= 0)
++ totalCount += bufCount;
++ break;
++ }
++ // JVM returned tp us with an intentional overflow!
++ totalCount += buf.length;
++ int excess = bufCount - buf.length;
++ if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
++ bufs.add(buf);
++ int len2 = buf.length;
++ len2 = Math.max(len2, excess);
++ len2 = Math.max(len2, totalCount / 4);
++ buf = newMemberBuffer(Math.min(BUF_MAX, len2));
++ }
++ ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount);
++ if (bufs != null) {
++ for (MemberName[] buf0 : bufs) {
++ Collections.addAll(result, buf0);
++ }
++ }
++ Collections.addAll(result, buf);
++ // Signature matching is not the same as type matching, since
++ // one signature might correspond to several types.
++ // So if matchType is a Class or MethodType, refilter the results.
++ if (matchType != null && matchType != matchSig) {
++ for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
++ MemberName m = it.next();
++ if (!matchType.equals(m.getType()))
++ it.remove();
++ }
++ }
++ return result;
++ }
++ boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> caller) {
++ MethodHandleNatives.resolve(m, caller);
++ if (m.isResolved()) return true;
++ int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
++ String matchSig = m.getSignature();
++ MemberName[] buf = { m };
++ int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
++ m.getName(), matchSig, matchFlags, caller, 0, buf);
++ if (n != 1) return false;
++ return m.isResolved();
++ }
++ public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> caller) {
++ MemberName result = m.clone();
++ if (resolveInPlace(result, searchSupers, caller))
++ return result;
++ return null;
++ }
++ public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> caller) {
++ MemberName result = resolveOrNull(m, searchSupers, caller);
++ if (result != null)
++ return result;
++ throw newNoAccessException(m, caller);
++ }
++ public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
++ Class<?> caller) {
++ return getMethods(defc, searchSupers, null, null, caller);
++ }
++ public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
++ String name, MethodType type, Class<?> caller) {
++ int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
++ return getMembers(defc, name, type, matchFlags, caller);
++ }
++ public List<MemberName> getConstructors(Class<?> defc, Class<?> caller) {
++ return getMembers(defc, null, null, IS_CONSTRUCTOR, caller);
++ }
++ public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
++ Class<?> caller) {
++ return getFields(defc, searchSupers, null, null, caller);
++ }
++ public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
++ String name, Class<?> type, Class<?> caller) {
++ int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
++ return getMembers(defc, name, type, matchFlags, caller);
++ }
++ public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
++ Class<?> caller) {
++ int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
++ return getMembers(defc, null, null, matchFlags, caller);
++ }
++ private static MemberName[] newMemberBuffer(int length) {
++ MemberName[] buf = new MemberName[length];
++ // fill the buffer with dummy structs for the JVM to fill in
++ for (int i = 0; i < length; i++)
++ buf[i] = new MemberName();
++ return buf;
++ }
++ }
++
++// static {
++// System.out.println("Hello world! My methods are:");
++// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
++// }
++}
+\ No newline at end of file
+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,266 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn;
++
++import java.dyn.MethodHandle;
++import java.dyn.MethodHandles;
++import java.dyn.MethodType;
++import impl.java.dyn.JavaMethodHandle;
++import impl.java.dyn.util.MethodHandleInvoker;
++import java.dyn.NoAccessException;
++import static impl.java.dyn.MemberName.newIllegalArgumentException;
++import static impl.java.dyn.MemberName.newNoAccessException;
+
+/**
+ * Base class for method handles which are known to the Hotspot JVM.
@@ -836,74 +2051,62 @@ new file mode 100644
+ Access.check(token);
+ }
+
++ /** Initialize the method type form to participate in JVM calls.
++ * This is done once for each erased type.
++ */
++ public static void init(Access token, MethodType self) {
++ Access.check(token);
++ if (MethodHandleNatives.JVM_SUPPORT)
++ MethodHandleNatives.init(self);
++ }
++
+ /// Factory methods to create method handles:
+
++ private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
++
++
+ /** Look up a given method.
-+ * Callable only from MethodHandles.
++ * Callable only from java.dyn and related packages.
++ * <p>
++ * The resulting method handle type will be of the given type,
++ * with a receiver type {@code rcvc} prepended if the member is not static.
++ * <p>
++ * Access checks are made as of the given caller.
++ * In particular, if the method is protected and {@code defc} is in a
++ * different package from the caller, then {@code rcvc} must be
++ * caller or a subclass.
+ * @param token Proof that the caller has access to this package.
-+ * @param defc Declaring class of the desired method.
++ * @param member Resolved method or constructor to call.
+ * @param name Name of the desired method.
+ * @param rcvc Receiver type of desired non-static method (else null)
-+ * @param 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
++ * @param doDispatch whether the method handle will test the receiver type
++ * @param caller if not null, access-check relative to this class ????
++ * @return a direct handle to the matching method
++ * @throws NoAccessException if the given method cannot be accessed by caller
+ */
+ 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) {
++ MethodHandle findMethod(Access token, MemberName method,
++ boolean doDispatch, Class<?> caller) {
++ Access.check(token); // only trusted calls
++ MethodType mtype = method.getMethodType();
++ if (method.isStatic()) {
++ doDispatch = false;
++ } else {
+ // adjust the advertised receiver type to be exactly the one requested
-+ 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);
++ // (in the case of invokespecial, this will be the calling class)
++ mtype = mtype.insertParameterType(0, method.getDeclaringClass());
++ if (method.isConstructor())
++ doDispatch = true;
++ }
++ DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, caller);
++ if (!mh.isValid())
++ throw newNoAccessException(method, caller);
++ return mh;
+ }
+
+ public static
+ MethodHandle accessField(Access token,
-+ Field f, boolean isSetter,
++ MemberName member, boolean isSetter,
+ Class<?> caller) {
+ Access.check(token);
+ // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
@@ -916,7 +2119,7 @@ new file mode 100644
+ Class<?> caller) {
+ Access.check(token);
+ if (!arrayClass.isArray())
-+ throw new IllegalArgumentException("not an array: "+arrayClass);
++ throw newIllegalArgumentException("not an array: "+arrayClass);
+ // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array.
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
@@ -924,43 +2127,44 @@ new file mode 100644
+ /** 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 target Any direct method handle.
+ * @param receiver Receiver (or first static method argument) to pre-bind.
+ * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
+ */
+ public static
+ MethodHandle bindReceiver(Access token,
-+ MethodHandle mh, Object receiver) {
++ MethodHandle target, Object receiver) {
+ Access.check(token);
-+ if (mh instanceof DirectMethodHandle)
-+ return new BoundMethodHandle((DirectMethodHandle)mh, receiver, 0);
++ if (target instanceof DirectMethodHandle)
++ return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
+ return null; // let caller try something else
+ }
+
+ /** Bind a predetermined argument to the given arbitrary method handle.
+ * Callable only from MethodHandles.
+ * @param token Proof that the caller has access to this package.
-+ * @param mh Any method handle.
++ * @param target Any method handle.
+ * @param receiver Argument (which can be a boxed primitive) to pre-bind.
+ * @return a suitable BoundMethodHandle
+ */
+ public static
+ MethodHandle bindArgument(Access token,
-+ MethodHandle mh, int argnum, Object receiver) {
++ MethodHandle target, int argnum, Object receiver) {
+ Access.check(token);
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ public static MethodHandle convertArguments(Access token,
-+ MethodHandle mh,
++ MethodHandle target,
+ MethodType newType,
-+ MethodType oldType) {
++ MethodType oldType,
++ String permutationOrNull) {
+ Access.check(token);
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ public static
-+ MethodHandle dropArguments(Access token, MethodHandle mh,
++ MethodHandle dropArguments(Access token, MethodHandle target,
+ MethodType newType, int argnum) {
+ Access.check(token);
+ throw new UnsupportedOperationException("NYI");
@@ -972,51 +2176,1197 @@ new file mode 100644
+ 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;
++ // %%% This is just a sketch. It needs to be de-boxed.
++ // Adjust the handles to accept varargs lists.
++ MethodType type = target.type();
++ Class<?> rtype = type.returnType();
++ if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) {
++ MethodType vatestType = MethodType.make(boolean.class, Object[].class);
++ MethodType vatargetType = MethodType.make(rtype, Object[].class);
++ MethodHandle vaguard = makeGuardWithTest(token,
++ MethodHandles.spreadArguments(test, vatestType),
++ MethodHandles.spreadArguments(target, vatargetType),
++ MethodHandles.spreadArguments(fallback, vatargetType));
++ return MethodHandles.collectArguments(vaguard, type);
++ }
++ if (rtype.isPrimitive()) {
++ MethodType boxtype = type.changeReturnType(Object.class);
++ MethodHandle boxguard = makeGuardWithTest(token,
++ test,
++ MethodHandles.convertArguments(target, boxtype),
++ MethodHandles.convertArguments(fallback, boxtype));
++ return MethodHandles.convertArguments(boxguard, type);
++ }
++ // Got here? Reduced calling sequence to Object(Object).
++ final MethodHandleInvoker invoke1
++ = MethodHandleInvoker.make(test.type());
++ final MethodHandleInvoker invoke2
++ = MethodHandleInvoker.make(target.type());
++ class Guarder {
++ Object invoke(Object x) {
+ // If javac supports MethodHandle.invoke directly:
+ //z = vatest.invoke<boolean>(arguments);
+ // If javac does not support direct MH.invoke calls:
-+ z = vatester.invoke_IL(vatest, arguments) != 0;
-+ return (z ? target : fallback);
++ boolean z = (Boolean) invoke1.invoke_1(test, x);
++ MethodHandle mh = (z ? target : fallback);
++ return invoke2.invoke_1(mh, x);
+ }
-+ }).methodHandle();
++ MethodHandle handle() {
++ MethodType invokeType = MethodType.makeGeneric(0, true);
++ MethodHandle vh = MethodHandles.bind(this, "invoke", invokeType);
++ return MethodHandles.collectArguments(vh, target.type());
++ }
++ }
++ return new Guarder().handle();
+ }
+
+ public static
-+ MethodHandle makeDispatcher(Access token, MethodHandle dispatcher, MethodType type) {
++ MethodHandle checkArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
+ 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.
++ protected static String basicToString(MethodHandle target) {
++ MemberName name = MethodHandleNatives.getMethodName(target);
++ if (name == null)
++ name = new MemberName(null, "<unknown>", target.type());
++ return name.toString();
++ }
++
++ static RuntimeException newIllegalArgumentException(String string) {
++ return new IllegalArgumentException(string);
++ }
++
++ @Override
++ public String toString() {
++ return basicToString((MethodHandle)this);
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/MethodHandleNatives.java b/src/share/classes/impl/java/dyn/MethodHandleNatives.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/MethodHandleNatives.java
+@@ -0,0 +1,240 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn;
++
++import java.dyn.MethodHandle;
++import java.dyn.MethodType;
++import java.lang.reflect.AccessibleObject;
++import java.lang.reflect.Field;
++import static impl.java.dyn.MethodHandleNatives.Constants.*;
++
++/**
++ * The JVM interface for the method handles package is all here.
++ * @author jrose
++ */
++class MethodHandleNatives {
++
++ private MethodHandleNatives() { } // static only
++
++ /// MethodName support
++
++ static native void init(MemberName self, Object ref);
++ static native void expand(MemberName self);
++ static native void resolve(MemberName self, Class<?> caller);
++ static native int getMembers(Class<?> defc, String matchName, String matchSig,
++ int matchFlags, Class<?> caller, int skip, MemberName[] results);
++
++ /// MethodHandle support
++
++ /** Initialize the method handle to adapt the call. */
++ static native void init(AdapterMethodHandle self, MethodHandle target, int argnum);
++ /** Initialize the method handle to call the correct method, directly. */
++ static native void init(BoundMethodHandle self, Object target, int argnum);
++ /** Initialize the method handle to call as if by an invoke* instruction. */
++ static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class<?> caller);
++
++ /** Initialize a method type, once per form. */
++ static native void init(MethodType self);
++
++ /** Tell the JVM that we need to change the target of an invokedynamic. */
++ static native void linkCallSite(CallSiteImpl site, MethodHandle target);
++
++ /** Fetch the vmtarget field.
++ * It will be sanitized as necessary to avoid exposing non-Java references.
++ * This routine is for debugging and reflection.
++ */
++ static native Object getTarget(MethodHandle self, int format);
++
++ /** Fetch the name of the handled method, if available.
++ * This routine is for debugging and reflection.
++ */
++ static MemberName getMethodName(MethodHandle self) {
++ if (!JVM_SUPPORT) return null;
++ return (MemberName) getTarget(self, ETF_METHOD_NAME);
++ }
++
++ /** Fetch the reflective version of the handled method, if available.
++ */
++ static AccessibleObject getTargetMethod(MethodHandle self) {
++ if (!JVM_SUPPORT) return null;
++ return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
++ }
++
++ /** Fetch the target of this method handle.
++ * If it directly targets a method, return a tuple of method info.
++ * The info is of the form new Object[]{defclass, name, sig, refclass}.
++ * If it is chained to another method handle, return that handle.
++ */
++ static Object getTargetInfo(MethodHandle self) {
++ if (!JVM_SUPPORT) return null;
++ return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
++ }
++
++ static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) {
++ return new Object[] { defc, name, sig, mods, refc };
++ }
++
++ /** Fetch MH-related JVM parameter.
++ * which=0 retrieves MethodHandlePushLimit
++ * which=1 retrieves stack slot push size (in address units)
++ */
++ static native int getConstant(int which);
++
++ /** True iff this HotSpot JVM has built-in support for method handles.
++ * If false, some test cases might run, but functionality will be missing.
++ */
++ public static final boolean JVM_SUPPORT;
++
++ /** Java copy of MethodHandlePushLimit in range 2..255. */
++ static final int JVM_PUSH_LIMIT;
++ /** JVM stack motion (in words) after one slot is pushed, usually -1.
++ */
++ static final int JVM_STACK_MOVE_UNIT;
++
++ private static native void registerNatives();
++ static {
++ boolean JVM_SUPPORT_;
++ int JVM_PUSH_LIMIT_;
++ int JVM_STACK_MOVE_UNIT_;
++ try {
++ registerNatives();
++ JVM_SUPPORT_ = true;
++ JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
++ JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT);
++ //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
++ } catch (UnsatisfiedLinkError ee) {
++ // ignore; if we use init() methods later we'll see linkage errors
++ JVM_SUPPORT_ = false;
++ JVM_PUSH_LIMIT_ = 3; // arbitrary
++ JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
++ }
++ 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");
++ }
++
++ // All compile-time constants go here.
++ // There is an opportunity to check them against the JVM's idea of them.
++ static class Constants {
++ Constants() { } // static only
++ // MethodHandleImpl
++ static final int // for getConstant
++ GC_JVM_PUSH_LIMIT = 0,
++ GC_JVM_STACK_MOVE_LIMIT = 1;
++ static final int
++ ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
++ ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
++ ETF_METHOD_NAME = 2, // ultimate method as MemberName
++ ETF_REFLECT_METHOD = 3; // ultimate method as java.lang.reflect object (sans refClass)
++
++ // MemberName
++ // The JVM uses values of -2 and above for vtable indexes.
++ // Field values are simple positive offsets.
++ // Ref: src/share/vm/oops/methodOop.hpp
++ // This value is negative enough to avoid such numbers,
++ // but not too negative.
++ static final int
++ MN_IS_METHOD = 0x00010000, // method (not constructor)
++ MN_IS_CONSTRUCTOR = 0x00020000, // constructor
++ MN_IS_FIELD = 0x00040000, // field
++ MN_IS_TYPE = 0x00080000, // nested type
++ MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
++ MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
++ VM_INDEX_UNINITIALIZED = -99;
++
++ // AdapterMethodHandle
++ /** Conversions recognized by the JVM.
++ * They must align with enum AdapterKind in vm/prims/methodHandles.hpp.
++ */
++ static final int
++ 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, // swap arguments (vminfo is 2nd arg)
++ ROT_ARGS = 0x600, // rotate arguments (vminfo is displaced arg)
++ DUP_ARGS = 0x700, // duplicates one or more arguments (at TOS)
++ DROP_ARGS = 0x800, // remove one or more argument slots
++ COLLECT_ARGS = 0x900, // combine one or more arguments into a varargs (NYI)
++ SPREAD_ARGS = 0xA00, // expand in place a varargs array (of known size)
++ FLYBY = 0xB00, // operate first on reified argument list (NYI)
++ RICOCHET = 0xC00; // 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 adapter BasicType (if needed)
++ CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
++ CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
++ CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
++
++ /**
++ * Basic types as encoded in the JVM. These code values are not
++ * intended for use outside this class. They are used as part of
++ * a private interface between the JVM and this class.
++ */
++ static final int
++ T_BOOLEAN = 4,
++ T_CHAR = 5,
++ T_FLOAT = 6,
++ T_DOUBLE = 7,
++ T_BYTE = 8,
++ T_SHORT = 9,
++ T_INT = 10,
++ T_LONG = 11,
++ T_OBJECT = 12,
++ //T_ARRAY = 13
++ T_VOID = 14;
++ //T_ADDRESS = 15
++ }
++
++ private static native int getNamedCon(int which, Object[] name);
++ static boolean verifyConstants() {
++ Object[] box = { null };
++ for (int i = 0; ; i++) {
++ box[0] = null;
++ int vmval = getNamedCon(i, box);
++ if (box[0] == null) break;
++ String name = (String) box[0];
++ try {
++ Field con = Constants.class.getDeclaredField(name);
++ int jval = con.getInt(null);
++ if (jval != vmval)
++ throw new InternalError(name+": JVM has "+vmval+" while Java has "+jval);
++ } catch (Exception ex) {
++ throw new InternalError(name+": access failed, got "+ex);
++ }
++ }
++ return true;
++ }
++ static {
++ if (JVM_SUPPORT) verifyConstants();
++ }
++}
+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-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++/**
++ * 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,455 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++import impl.java.dyn.Access;
++import impl.java.dyn.AdapterMethodHandle;
++import java.dyn.AnonymousClassLoader;
++import java.dyn.ConstantPoolParser;
++import java.dyn.ConstantPoolPatch;
++import java.dyn.ConstantPoolVisitor;
++import java.dyn.InvalidConstantPoolFormatException;
++import java.dyn.MethodHandle;
++import java.dyn.MethodHandles;
++import java.dyn.MethodType;
++import java.dyn.WrongMethodTypeException;
++import java.io.IOException;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++import java.util.IdentityHashMap;
++
++/**
++ * Emulation of method handle invocation.
++ * Not needed if javac supports direct invocation of MethodHandle.invoke.
++ * @author jrose
++ */
++public abstract
++class MethodHandleInvoker implements Cloneable {
++ private static final Access IMPL_TOKEN = Access.getToken();
++
++
++ /** Exact type for all handles targeted by this invoker. */
++ protected final MethodType exactType;
++
++ /** Condensed information about the return type, one of "VLIJFDZBSC". */
++ protected final char rtypec;
++
++ /** Adapter which converts the approximate type to the exact exactType. */
++ protected final MethodHandle adapter;
++
++ /** Maximum number of arguments allowed.
++ * This is an implementation limit.
++ */
++ public static final int ARGUMENT_MAX;
++ /** Maximum number of double or long arguments allowed.
++ * This is an implementation limit.
++ */
++ public static final int LONG_ARGUMENT_MAX;
++ static {
++ LONG_ARGUMENT_MAX = 3; // %%% depends on stack headroom
++ }
++
++ public MethodType type() { return exactType; }
++
++ protected MethodHandleInvoker(MethodType exactType, MethodHandle adapter) {
++ this.exactType = exactType;
++ this.rtypec = Wrappers.basicTypeChar(exactType.returnType());
++ this.adapter = adapter;
++ }
++
++ static MethodHandle makeAdapter(MethodType exactType, MethodType approxType) {
++ // For each argument, convert incoming Object to the exact type needed.
++ int len = exactType.parameterCount();
++ assert(len == approxType.parameterCount());
++ if (exactType.parameterSlotCount() > len + LONG_ARGUMENT_MAX)
++ throw new IllegalArgumentException("too many long arguments in "+exactType);
++ MethodHandle invoker = MethodHandles.findVirtual(MethodHandle.class, "invoke", exactType);
++ MethodType adapterType = approxType.insertParameterType(0, MethodHandle.class);
++ return AdapterMethodHandle.makePairwiseConversion(IMPL_TOKEN, adapterType, invoker);
++ }
++
++ public Object invoke_0(MethodHandle mh)
++ { throw wrongType(mh); }
++ public Object invoke_1(MethodHandle mh, Object a0)
++ { throw wrongType(mh); }
++ public Object invoke_2(MethodHandle mh, Object a0, Object a1)
++ { throw wrongType(mh); }
++ public Object invoke_3(MethodHandle mh, Object a0, Object a1, Object a2)
++ { throw wrongType(mh); }
++ public Object invoke_4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3)
++ { throw wrongType(mh); }
++ public Object invoke_5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4)
++ { throw wrongType(mh); }
++
++ /** Reflective style generic invocation. This always delegates
++ * to one of the invoke_X methods.
++ * @param mh method handle to invoke (must be of exactly correct type)
++ * @param args array of arguments to send to method (maybe null if empty)
++ * @return
++ */
++ final // try this...
++ public Object invoke(MethodHandle mh, Object ... args) {
++ switch (args == null ? 0 : args.length) {
++ case 0: return invoke_0(mh);
++ case 1: return invoke_1(mh, args[0]);
++ case 2: return invoke_2(mh, args[0], args[1]);
++ case 3: return invoke_3(mh, args[0], args[1], args[2]);
++ case 4: return invoke_4(mh, args[0], args[1], args[2], args[3]);
++ case 5: return invoke_5(mh, args[0], args[1], args[2], args[3], args[4]);
++ }
++ throw wrongType(mh);
++ }
++
++ // This class is not used after compile time.
++ // It is renamed away to MethodHandle itself, to call the MHI.adapter.
++ // TO DO: Update javac so we can call directly to polymorphic MH.invoke.
++ private static abstract class FakeMethodHandle extends MethodHandle {
++ public FakeMethodHandle() { super(null, null); }
++ // here are all the invokes we need to link against:
++ public abstract void fake_invoke_V0(MethodHandle mh);
++ public abstract Object fake_invoke_L0(MethodHandle mh);
++ public abstract int fake_invoke_I0(MethodHandle mh);
++ public abstract long fake_invoke_J0(MethodHandle mh);
++ public abstract double fake_invoke_F0(MethodHandle mh);
++ public abstract double fake_invoke_D0(MethodHandle mh);
++ public abstract void fake_invoke_V1(MethodHandle mh, Object a0);
++ public abstract Object fake_invoke_L1(MethodHandle mh, Object a0);
++ public abstract int fake_invoke_I1(MethodHandle mh, Object a0);
++ public abstract long fake_invoke_J1(MethodHandle mh, Object a0);
++ public abstract float fake_invoke_F1(MethodHandle mh, Object a0);
++ public abstract double fake_invoke_D1(MethodHandle mh, Object a0);
++ public abstract void fake_invoke_V2(MethodHandle mh, Object a0, Object a1);
++ public abstract Object fake_invoke_L2(MethodHandle mh, Object a0, Object a1);
++ public abstract int fake_invoke_I2(MethodHandle mh, Object a0, Object a1);
++ public abstract long fake_invoke_J2(MethodHandle mh, Object a0, Object a1);
++ public abstract float fake_invoke_F2(MethodHandle mh, Object a0, Object a1);
++ public abstract double fake_invoke_D2(MethodHandle mh, Object a0, Object a1);
++ public abstract void fake_invoke_V3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract Object fake_invoke_L3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract int fake_invoke_I3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract long fake_invoke_J3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract float fake_invoke_F3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract double fake_invoke_D3(MethodHandle mh, Object a0, Object a1, Object a2);
++ public abstract void fake_invoke_V4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract Object fake_invoke_L4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract int fake_invoke_I4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract long fake_invoke_J4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract float fake_invoke_F4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract double fake_invoke_D4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
++ public abstract void fake_invoke_V5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ public abstract Object fake_invoke_L5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ public abstract int fake_invoke_I5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ public abstract long fake_invoke_J5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ public abstract float fake_invoke_F5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ public abstract double fake_invoke_D5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
++ }
++ private static String FMHInvokeName(MethodType approxType) {
++ assert(isFMHInvokeType(approxType)) : approxType;
++ return "fake_invoke_"
++ + Wrappers.basicTypeChar(approxType.returnType())
++ + approxType.parameterCount();
++ }
++ private static boolean isFMHInvokeType(MethodType approxType) {
++ Class<?> rtype = approxType.returnType();
++ char rtc = Wrappers.basicTypeChar(approxType.returnType());
++ if ("VIJFD".indexOf(rtc) < 0 && rtype != Object.class)
++ return false;
++ int len = approxType.parameterCount();
++ for (int i = 0; i < len; i++)
++ if (approxType.parameterType(i) != Object.class)
++ return false;
++ if (approxType.isVarArgs()) return false;
++ return true;
++ }
++
++ protected Object wrap(int value) {
++ switch (rtypec) {
++ case 'Z': return (value != 0);
++ case 'B': return (byte)value;
++ case 'S': return (short)value;
++ case 'C': return (char)value;
++ }
++ return value;
++ }
++
++ static class L0 extends MethodHandleInvoker {
++ public L0(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_0(MethodHandle mh) {
++ checkType(mh);
++ switch (rtypec) {
++ // Note: Could unswitch this into 5 classes, but too messy.
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L0(mh);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I0(mh));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J0(mh);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F0(mh);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D0(mh);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V0(mh);
++ /* Here is the sort of code we will use when we get javac support:
++ case 'L': return adapter.invoke(mh);
++ default: return wrap(adapter.<int>invoke(mh));
++ case 'J': return adapter.<long>invoke(mh);
++ case 'F': return adapter.<float>invoke(mh);
++ case 'D': return adapter.<double>invoke(mh);
++ case 'V': adapter.<void>invoke(mh);
++ */
++ }
++ return null;
++ }
++ }
++
++ static class L1 extends MethodHandleInvoker {
++ public L1(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_1(MethodHandle mh, Object a0) {
++ checkType(mh);
++ switch (rtypec) {
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L1(mh, a0);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I1(mh, a0));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J1(mh, a0);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F1(mh, a0);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D1(mh, a0);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V1(mh, a0);
++ }
++ return null;
++ }
++ }
++
++ static class L2 extends MethodHandleInvoker {
++ public L2(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_2(MethodHandle mh, Object a0, Object a1) {
++ checkType(mh);
++ switch (rtypec) {
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L2(mh, a0, a1);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I2(mh, a0, a1));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J2(mh, a0, a1);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F2(mh, a0, a1);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D2(mh, a0, a1);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V2(mh, a0, a1);
++ }
++ return null;
++ }
++ }
++
++ static class L3 extends MethodHandleInvoker {
++ public L3(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_3(MethodHandle mh, Object a0, Object a1, Object a2) {
++ checkType(mh);
++ switch (rtypec) {
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L3(mh, a0, a1, a2);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I3(mh, a0, a1, a2));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J3(mh, a0, a1, a2);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F3(mh, a0, a1, a2);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D3(mh, a0, a1, a2);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V3(mh, a0, a1, a2);
++ }
++ return null;
++ }
++ }
++
++ static class L4 extends MethodHandleInvoker {
++ public L4(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3) {
++ checkType(mh);
++ switch (rtypec) {
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L4(mh, a0, a1, a2, a3);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I4(mh, a0, a1, a2, a3));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J4(mh, a0, a1, a2, a3);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F4(mh, a0, a1, a2, a3);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D4(mh, a0, a1, a2, a3);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V4(mh, a0, a1, a2, a3);
++ }
++ return null;
++ }
++ }
++
++ static class L5 extends MethodHandleInvoker {
++ public L5(MethodType type, MethodHandle adapter) { super(type, adapter); }
++ @Override public Object invoke_5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4) {
++ checkType(mh);
++ switch (rtypec) {
++ case 'L': return ((FakeMethodHandle)adapter).fake_invoke_L5(mh, a0, a1, a2, a3, a4);
++ default: return wrap(((FakeMethodHandle)adapter).fake_invoke_I5(mh, a0, a1, a2, a3, a4));
++ case 'J': return ((FakeMethodHandle)adapter).fake_invoke_J5(mh, a0, a1, a2, a3, a4);
++ case 'F': return ((FakeMethodHandle)adapter).fake_invoke_F5(mh, a0, a1, a2, a3, a4);
++ case 'D': return ((FakeMethodHandle)adapter).fake_invoke_D5(mh, a0, a1, a2, a3, a4);
++ case 'V': ((FakeMethodHandle)adapter).fake_invoke_V5(mh, a0, a1, a2, a3, a4);
++ }
++ return null;
++ }
++ }
++
++ private static Class<?>[] L_CLASSES
++ = { L0.class, L1.class, L2.class, L3.class, L4.class, L5.class };
++ static { ARGUMENT_MAX = L_CLASSES.length + 1; }
++
++ public static MethodHandleInvoker make(MethodType type) {
++ MethodHandleInvoker inv = null;
++ synchronized (invokers) {
++ inv = invokers.get(type);
++ }
++ if (inv != null) return inv;
++ inv = makeNew(type);
++ synchronized (invokers) {
++ MethodHandleInvoker inv2 = invokers.get(type);
++ if (inv2 == null)
++ invokers.put(type, inv);
++ else
++ inv = inv2;
++ }
++ System.out.println("new invoker: "+inv);
++ return inv;
++ }
++
++ static MethodType approxType(MethodType exactType) {
++ int len = exactType.parameterCount();
++ if (len > ARGUMENT_MAX || exactType.isVarArgs())
++ throw new IllegalArgumentException("too many arguments for invoker: "+exactType);
++ // The JVM can insert casts and unboxing for us in a native adapter.
++ MethodType approxType = MethodType.makeGeneric(len);
++ // But the return type must be exact, except for subword types.
++ // Convert subwords to int, since the JVM an narrow them back down.
++ Class<?> rtype = exactType.returnType();
++ switch (Wrappers.basicTypeChar(rtype)) {
++ case 'L':
++ rtype = Object.class; break;
++ case 'Z': case 'B': case 'S': case 'C':
++ rtype = int.class; break;
++ }
++ approxType = approxType.changeReturnType(rtype);
++ return approxType;
++ }
++
++ private static MethodHandleInvoker makeNew(MethodType exactType) {
++ MethodHandleInvoker inv = null;
++ Exception ex1 = null;
++ MethodType approxType = approxType(exactType);
++ MethodHandle adapter = makeAdapter(exactType, approxType);
++ Class<? extends MethodHandleInvoker> template = null;
++ Class<? extends MethodHandleInvoker> instance = null;
++ Constructor<? extends MethodHandleInvoker> constr = null;
++ template = L_CLASSES[approxType.parameterCount()].asSubclass(MethodHandleInvoker.class);
++ {
++ try {
++ instance = expandTemplate(template, approxType, exactType);
++ // When we get rid of the fakery, it will be just
++ // constr = template.getConstructor
++ constr = instance.getConstructor(MethodType.class, MethodHandle.class);
++ inv = constr.newInstance(exactType, adapter);
++ } catch (IOException ex) {
++ ex1 = ex;
++ } catch (InvalidConstantPoolFormatException ex) {
++ ex1 = ex;
++ } catch (InstantiationException ex) {
++ ex1 = ex;
++ } catch (IllegalAccessException ex) {
++ ex1 = ex;
++ } catch (NoSuchMethodException ex) {
++ ex1 = ex;
++ } catch (IllegalArgumentException ex) {
++ ex1 = ex;
++ } catch (InvocationTargetException ex) {
++ ex1 = ex;
++ }
++ }
++ if (inv == null) {
++ printex(ex1);
++ throw new InternalError();
++ }
++ return inv;
++ }
++ private static void printex(Exception ex) {
++ System.out.println("*** Unexpected exception in "+MethodHandleInvoker.class);
++ System.out.println(ex);
++ ex.printStackTrace(System.out);
++ }
++
++ private static final AnonymousClassLoader LOADER
++ = new AnonymousClassLoader(MethodHandleInvoker.class);
++
++ private static String utf8Name(Class<?> cls) {
++ return cls.getName().replace('.', '/');
++ }
++
++ private static class TemplateExpander extends ConstantPoolVisitor {
++ ConstantPoolParser cp;
++ ConstantPoolPatch patch;
++
++ // Pairs of strings to be rewritten:
++ String fakeMHName = utf8Name(FakeMethodHandle.class);
++ String realMHName = utf8Name(MethodHandle.class);
++ boolean didMHName;
++
++ String fakeInvokeName, realInvokeName = "invoke";
++ boolean didInvokeName;
++
++ @Override
++ public void visitUTF8(int index, byte tag, String utf8) {
++ String orig = utf8;
++ if (utf8.equals(fakeMHName)) {
++ utf8 = realMHName; didMHName = true;
++ }
++ if (utf8.equals(fakeInvokeName)) {
++ utf8 = realInvokeName; didInvokeName = true;
++ }
++ if ((Object)utf8 != orig)
++ patch.putUTF8(index, utf8);
++ }
++
++ public TemplateExpander(Class<? extends MethodHandleInvoker> template,
++ MethodType approxType, MethodType exactType)
++ throws IOException, InvalidConstantPoolFormatException {
++ // construct a descriptor of something like:
++ // int fake_invoke_I2(MethodHandle, Object, Object);
++ fakeInvokeName = FMHInvokeName(approxType);
++ cp = new ConstantPoolParser(template);
++ patch = cp.createPatch();
++ cp.parse(this);
++ if (!(didMHName && didInvokeName))
++ throw new RuntimeException("utf8 rewrites failed: "
++ +(!didMHName?"":fakeMHName)+(!didInvokeName?"":fakeInvokeName));
++ }
++ }
++
++ static final IdentityHashMap<MethodType,MethodHandleInvoker> invokers
++ = new IdentityHashMap<MethodType, MethodHandleInvoker>();
++
++ private static Class<? extends MethodHandleInvoker>
++ expandTemplate(Class<? extends MethodHandleInvoker> template,
++ MethodType approxType, MethodType exactType)
++ throws IOException, InvalidConstantPoolFormatException {
++ TemplateExpander tex = new TemplateExpander(template, approxType, exactType);
++ return LOADER.loadClass(tex.patch).asSubclass(MethodHandleInvoker.class);
++ }
++
++ /** Throw this if a bad entry point is taken. */
++ protected RuntimeException wrongType(MethodHandle mh) {
++ return new WrongMethodTypeException("wrong call type for "+mh+
++ " should be "+exactType+" in "+this);
++ }
++ protected void checkType(MethodHandle mh) {
++ if (mh.type() != exactType)
++ throw wrongType(mh);
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/util/Signatures.java b/src/share/classes/impl/java/dyn/util/Signatures.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/Signatures.java
+@@ -0,0 +1,133 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++import java.dyn.MethodType;
++import java.util.ArrayList;
++import java.util.List;
++
++public class Signatures {
++
++ private Signatures() { } // cannot instantiate
++
++ public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
++ return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
++ }
++
++ public static List<Class<?>> parseMethod(String bytecodeSignature,
++ int start, int end, ClassLoader loader) {
++ if (loader == null)
++ loader = ClassLoader.getSystemClassLoader();
++ String str = bytecodeSignature;
++ int[] i = {start};
++ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
++ if (i[0] < end && str.charAt(i[0]) == '(') {
++ ++i[0]; // skip '('
++ while (i[0] < end && str.charAt(i[0]) != ')') {
++ Class<?> pt = parseSig(str, i, end, loader);
++ if (pt == null || pt == void.class)
++ parseError(str, "bad argument type");
++ ptypes.add(pt);
++ }
++ ++i[0]; // skip ')'
++ } else {
++ parseError(str, "not a method type");
++ }
++ Class<?> rtype = parseSig(str, i, end, loader);
++ if (rtype == null || i[0] != end)
++ parseError(str, "bad return type");
++ ptypes.add(rtype);
++ return ptypes;
++ }
++
++ static private void parseError(String str, String msg) {
++ throw new IllegalArgumentException("bad signature: "+str+": "+msg);
++ }
++
++ static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
++ if (i[0] == end) return null;
++ char c = str.charAt(i[0]++);
++ if (c == 'L') {
++ int begc = i[0], endc = str.indexOf(';', begc);
++ if (endc < 0) return null;
++ i[0] = endc+1;
++ String name = str.substring(begc, endc).replace('/', '.');
++ try {
++ return loader.loadClass(name);
++ } catch (ClassNotFoundException ex) {
++ throw new TypeNotPresentException(name, ex);
++ }
++ } else if (c == '[') {
++ Class<?> t = parseSig(str, i, end, loader);
++ if (t != null)
++ t = java.lang.reflect.Array.newInstance(t, 0).getClass();
++ return t;
++ } else {
++ return Wrappers.basicTypeFromChar(c);
++ }
++ }
++
++ public static String unparse(Class<?> type) {
++ StringBuilder sb = new StringBuilder();
++ unparseSig(type, sb);
++ return sb.toString();
++ }
++
++ public static String unparse(MethodType type) {
++ return unparseMethod(type.returnType(), type.parameterList());
++ }
++
++ public static String unparse(Object type) {
++ if (type instanceof Class<?>)
++ return unparse((Class<?>) type);
++ if (type instanceof MethodType)
++ return unparse((MethodType) type);
++ return (String) type;
++ }
++
++ public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
++ StringBuilder sb = new StringBuilder();
++ sb.append('(');
++ for (Class<?> pt : ptypes)
++ unparseSig(pt, sb);
++ sb.append(')');
++ unparseSig(rtype, sb);
++ return sb.toString();
++ }
++
++ static private void unparseSig(Class<?> t, StringBuilder sb) {
++ char c = Wrappers.basicTypeChar(t);
++ if (c != 'L') {
++ sb.append(c);
++ } else {
++ boolean lsemi = (!t.isArray());
++ if (lsemi) sb.append('L');
++ sb.append(t.getName().replace('.', '/'));
++ if (lsemi) sb.append(';');
++ }
++ }
++
++}
+diff --git a/src/share/classes/impl/java/dyn/util/VerifyAccess.java b/src/share/classes/impl/java/dyn/util/VerifyAccess.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/VerifyAccess.java
+@@ -0,0 +1,135 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++import impl.java.dyn.MemberName;
++import java.lang.reflect.Method;
++import java.lang.reflect.Modifier;
++import java.util.Arrays;
++
++/**
++ * This class centralizes information about the JVM's linkage access control.
++ * @author jrose
++ */
++public class VerifyAccess {
++
++ private VerifyAccess() { } // cannot instantiate
++
++ /**
++ * Evaluate the JVM linkage rules for access to the given method on behalf of caller.
++ * Return non-null if and only if the given accessing class has at least partial
++ * privileges to invoke the given method. The return value {@code Object.class}
++ * denotes unlimited privileges.
++ * <p>
++ * Some circumstances require an additional check on the
++ * leading parameter (the receiver) of the method, if it is non-static.
++ * In the case of {@code invokespecial} ({@code doDispatch} is false),
++ * the leading parameter must be the accessing class or a subclass.
++ * In the case of a call to a {@code protected} method outside the same
++ * package, the same constraint applies.
++ * @param m the proposed callee
++ * @param doDispatch if false, a non-static m will be invoked as if by {@code invokespecial}
++ * @param accessingClass the class for which the access check is being made
++ * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class}
++ */
++ public static Class<?> isAccessible(Class<?> defc, int mods,
++ boolean doDispatch, Class<?> accessingClass) {
++ if (!isAccessible(defc, accessingClass))
++ return null;
++ Class<?> constraint = Object.class;
++ if (!doDispatch && !Modifier.isStatic(mods)) {
++ constraint = accessingClass;
++ }
++ if (Modifier.isPublic(mods))
++ return constraint;
++ if (Modifier.isPrivate(mods))
++ return (defc == accessingClass) ? constraint : null;
++ if (isSamePackage(defc, accessingClass))
++ return constraint;
++ if (Modifier.isProtected(mods) && defc.isAssignableFrom(accessingClass))
++ return constraint;
++ // else it is private or package scoped, and not close enough
++ return null;
++ }
++
++ /**
++ * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
++ */
++ public static boolean isAccessible(Class<?> refc, Class<?> accessingClass) {
++ int mods = refc.getModifiers();
++ if (Modifier.isPublic(mods))
++ return true;
++ if (isSamePackage(accessingClass, refc))
++ return true;
++ return false;
++ }
++
++ /**
++ * Test if two classes have the same class loader and package qualifier.
++ * @param class1
++ * @param class2
++ * @return whether they are in the same package
++ */
++ public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
++ if (class1 == class2)
++ return true;
++ if (class1.getClassLoader() != class2.getClassLoader())
++ return false;
++ String name1 = class1.getName(), name2 = class2.getName();
++ int dot = name1.lastIndexOf('.');
++ if (dot != name2.lastIndexOf('.'))
++ return false;
++ for (int i = 0; i < dot; i++) {
++ if (name1.charAt(i) != name2.charAt(i))
++ return false;
++ }
++ return true;
++ }
++
++ /**
++ * Test if two classes are defined as part of the same package member (top-level class).
++ * If this is true, they can share private access with each other.
++ * @param class1
++ * @param class2
++ * @return whether they are identical or nested together
++ */
++ public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
++ if (class1 == class2)
++ return true;
++ if (!isSamePackage(class1, class2))
++ return false;
++ if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
++ return false;
++ return true;
++ }
++
++ private static Class<?> getOutermostEnclosingClass(Class<?> c) {
++ Class<?> pkgmem = c;
++ for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
++ pkgmem = enc;
++ return pkgmem;
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/util/VerifyType.java b/src/share/classes/impl/java/dyn/util/VerifyType.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/VerifyType.java
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++import java.dyn.MethodType;
++
++/**
++ * This class centralizes information about the JVM verifier
++ * and its requirements about type correctness.
++ * @author jrose
++ */
++public class VerifyType {
++
++ private VerifyType() { } // cannot instantiate
++
++ /**
++ * True if a value can be stacked as the source type and unstacked as the
++ * destination type, without violating the JVM's type consistency.
++ *
++ * @param call the type of a stacked value
++ * @param recv the type by which we'd like to treat it
++ * @return whether the retyping can be done without motion or reformatting
++ */
++ public static boolean isNullConversion(Class<?> src, Class<?> dst) {
++ if (src == dst) return true;
++ // Verifier allows any interface to be treated as Object:
++ if (dst.isInterface()) dst = Object.class;
++ if (src.isInterface()) src = Object.class;
++ if (src == dst) return true; // check again
++ if (dst == void.class) return true; // drop any return value
++ if (!src.isPrimitive()) return dst.isAssignableFrom(src);
++ // Verifier allows an int to carry byte, short, char, or even boolean:
++ if (dst == int.class) return Wrappers.isSubwordOrInt(src);
++ return false;
++ }
++
++ /**
++ * True if a method handle can receive a call under a slightly different
++ * method type, without moving or reformatting any stack elements.
++ *
++ * @param call the type of call being made
++ * @param recv the type of the method handle receiving the call
++ * @return whether the retyping can be done without motion or reformatting
++ */
++ public static boolean isNullConversion(MethodType call, MethodType recv) {
++ if (call == recv) return true;
++ int len = call.parameterCount();
++ if (len != recv.parameterCount()) return false;
++ for (int i = 0; i < len; i++)
++ if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
++ return false;
++ return isNullConversion(recv.returnType(), call.returnType());
++ }
++
++ /**
++ * Determine if the JVM verifier allows a value of type call to be
++ * passed to a formal parameter (or return variable) of type recv.
+ * 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>conversion between any two integral types (but not floats)
+ * </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)
++ public static int canPassUnchecked(Class<?> src, Class<?> dst) {
++ if (src == dst)
+ return 1;
+
-+ if (dest.isPrimitive()) {
-+ if (dest == void.class)
++ if (dst.isPrimitive()) {
++ if (dst == void.class)
+ // Return anything to a caller expecting void.
+ return 1;
+ if (src == void.class)
@@ -1025,15 +3375,15 @@ new file mode 100644
+ // Cannot pass a reference to any primitive type (exc. void).
+ return 0;
+ boolean swt = Wrappers.isSubwordOrInt(src);
-+ boolean dwt = Wrappers.isSubwordOrInt(dest);
++ boolean dwt = Wrappers.isSubwordOrInt(dst);
+ if (swt && dwt) {
-+ if (Wrappers.bitWidth(src) >= Wrappers.bitWidth(dest))
++ if (Wrappers.bitWidth(src) >= Wrappers.bitWidth(dst))
+ return -1; // truncation may be required
-+ if (!Wrappers.isSigned(dest) && Wrappers.isSigned(src))
++ if (!Wrappers.isSigned(dst) && Wrappers.isSigned(src))
+ return -1; // sign elimination may be required
+ }
-+ if (src == float.class || dest == float.class) {
-+ if (src == double.class || dest == double.class)
++ if (src == float.class || dst == float.class) {
++ if (src == double.class || dst == double.class)
+ return -1; // floating conversion may be required
+ else
+ return 0; // other primitive conversions NYI
@@ -1050,132 +3400,23 @@ new file mode 100644
+ // 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)
++ if (dst.isInterface()) dst = Object.class;
++ //if (call.isInterface()) call = Object.class;
++ if (dst == 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
+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/package-info.java
-@@ -0,0 +1,35 @@
++++ b/src/share/classes/impl/java/dyn/util/Wrappers.java
+@@ -0,0 +1,272 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -1199,392 +3440,17 @@ new file mode 100644
+ * 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
+
++ /** If {@code type} is a primitive type, return the corresponding
++ * wrapper type, else return {@code type} unchanged.
++ */
+ public static <T> Class<T> asWrapperType(Class<T> type) {
+ if (!type.isPrimitive()) {
+ return type;
@@ -1597,6 +3463,9 @@ new file mode 100644
+ return (Class<T>) memo[0]; // unchecked warning is OK here
+ }
+
++ /** If {@code type} is a wrapper type, return the corresponding
++ * primitive type, else return {@code type} unchanged.
++ */
+ public static <T> Class<T> asPrimitiveType(Class<T> type) {
+ if (type.isPrimitive()) {
+ return type;
@@ -1615,6 +3484,10 @@ new file mode 100644
+ return asPrimitiveType(type) != type;
+ }
+
++ public static boolean isPrimitiveType(Class<?> type) {
++ return type.isPrimitive();
++ }
++
+ public static char basicTypeChar(Class<?> type) {
+ if (!type.isPrimitive()) {
+ return 'L';
@@ -1628,7 +3501,7 @@ new file mode 100644
+ }
+
+ static final String PRIMITIVE_BITS_TABLE = "LZBCSFIZZDJ";
-+ // "--012345678"
++ // "--01234 78"
+
+ /** Return the number of bits in the given type, or zero for refs. */
+ public static int bitWidth(Class<?> type) {
@@ -1648,16 +3521,39 @@ new file mode 100644
+ }
+ }
+
-+ /** Return the number of bits in the given type, or zero for refs. */
++ static final String PRIMITIVE_SIGN_TABLE = "JZICSZB";
++ // "SuSuS S"
++ /** Return whether the given type is a signed integral type. */
+ public static boolean isSigned(Class<?> type) {
+ return isSigned(basicTypeChar(type));
+ }
+
-+ /** Return the number of bits in the given basic type, or zero for refs. */
++ /** Return whether the given type is a signed integral type. */
+ public static boolean isSigned(char c) {
-+ int i = PRIMITIVE_BITS_TABLE.indexOf(c);
-+ assert(c != ' ' && (i >= 0 || c == 'L'));
++ int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
+ return (i & 1) == 0;
++ }
++
++ /** Return whether the given type is a unsigned integral type. */
++ public static boolean isUnsigned(Class<?> type) {
++ return isUnsigned(basicTypeChar(type));
++ }
++
++ /** Return whether the given type is a unsigned integral type. */
++ public static boolean isUnsigned(char c) {
++ int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
++ return (i & 0x11) == 1;
++ }
++
++ /** Return whether the given type is an integral type. */
++ public static boolean isIntegral(Class<?> type) {
++ return isIntegral(basicTypeChar(type));
++ }
++
++ /** Return whether the given type is an integral type. */
++ public static boolean isIntegral(char c) {
++ int i = PRIMITIVE_SIGN_TABLE.indexOf(c);
++ return i >= 0;
+ }
+
+ /** Report if the type is one of int, boolean, byte, char, or short. */
@@ -1667,7 +3563,17 @@ new file mode 100644
+
+ /** Report if the type char is one of "IZBCS". */
+ public static boolean isSubwordOrInt(char c) {
-+ return "IZBCS".indexOf(c) >= 0;
++ return PRIMITIVE_SIGN_TABLE.indexOf(c) > 0;
++ }
++
++ /** Return whether the given type is a floating primitive type. */
++ public static boolean isFloating(Class<?> type) {
++ return isFloating(basicTypeChar(type));
++ }
++
++ /** Return whether the given type is a floating primitive type. */
++ public static boolean isFloating(char c) {
++ return c == 'F' || c == 'D';
+ }
+
+ /** Return the primitive type that corresponds to the given bytecode
@@ -1703,8 +3609,13 @@ new file mode 100644
+ }
+
+ public static <T> T wrap(Object x, Class<T> numClass) {
-+ Class<T> primitiveType = asPrimitiveType(numClass);
-+ return numClass.cast(wrap(x, basicTypeChar(primitiveType)));
++ if (wrappers.isEmpty()) {
++ fillWrappers();
++ }
++ Object[] memo = wrappers.get(numClass);
++ if (memo == null) return numClass.cast(x); // no change
++ Class<T> wrapType = (Class<T>) memo[0]; // unchecked warning is OK here
++ return wrapType.cast(wrap(x, (Character) memo[2]));
+ }
+ public static Object wrap(Object x, char c) {
+ Number xn = numberValue(x);
@@ -1782,7 +3693,7 @@ new file mode 100644
+++ b/src/share/classes/impl/java/dyn/util/package-info.java
@@ -0,0 +1,31 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -1818,7 +3729,7 @@ new file mode 100644
+++ b/src/share/classes/java/dyn/CallSite.java
@@ -0,0 +1,116 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -1939,7 +3850,7 @@ new file mode 100644
+++ b/src/share/classes/java/dyn/Dynamic.java
@@ -0,0 +1,50 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -1988,13 +3899,13 @@ new file mode 100644
+public interface Dynamic {
+ // no methods
+}
-diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
+diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/java/dyn/Linkage.java
-@@ -0,0 +1,211 @@
++++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+@@ -0,0 +1,53 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -2020,197 +3931,39 @@ new file mode 100644
+
+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.
++ * Thrown to indicate that an {@code invokedynamic} instruction has
++ * failed to find its bootstrap method.
++ * This must have been declared during a class's initialization
++ * by a call to {@link Linkage#registerBootstrapMethod}.
++ *
+ * @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));
-+ }
-+
++public class InvokeDynamicBootstrapError extends LinkageError {
++ /**
++ * Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
++ */
++ public InvokeDynamicBootstrapError() {
++ super();
++ }
++
++ /**
++ * Constructs a {@code InvokeDynamicBootstrapError} with the specified
++ * detail message.
++ *
++ * @param s the detail message.
++ */
++ public InvokeDynamicBootstrapError(String s) {
++ super(s);
++ }
+}
-diff --git a/src/share/classes/java/dyn/LinkagePermission.java b/src/share/classes/java/dyn/LinkagePermission.java
+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/LinkagePermission.java
-@@ -0,0 +1,111 @@
++++ b/src/share/classes/java/dyn/Linkage.java
+@@ -0,0 +1,211 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -2236,6 +3989,222 @@ new file mode 100644
+
+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(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-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package java.dyn;
++
+import java.security.*;
+import java.util.Enumeration;
+import java.util.Hashtable;
@@ -2326,7 +4295,7 @@ new file mode 100644
+++ b/src/share/classes/java/dyn/MethodHandle.java
@@ -0,0 +1,129 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -2458,9 +4427,9 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/MethodHandles.java
-@@ -0,0 +1,714 @@
+@@ -0,0 +1,940 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -2486,16 +4455,20 @@ new file mode 100644
+
+package java.dyn;
+
++import impl.java.dyn.Access;
++import impl.java.dyn.MemberName;
++import impl.java.dyn.MethodHandleImpl;
++import impl.java.dyn.util.MethodHandleInvoker;
++import impl.java.dyn.util.VerifyAccess;
+import impl.java.dyn.util.Wrappers;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
++import java.lang.reflect.Modifier;
+import java.util.ArrayList;
++import java.util.Arrays;
+import sun.reflect.Reflection;
-+
-+//import java.dyn.emu.*;
-+import impl.java.dyn.*;
-+import java.util.Arrays;
-+import java.util.List;
++import static impl.java.dyn.MemberName.newIllegalArgumentException;
++import static impl.java.dyn.MemberName.newNoAccessException;
+
+/**
+ * Fundamental operations and utilities for MethodHandle.
@@ -2517,6 +4490,7 @@ new file mode 100644
+ private MethodHandles() { } // do not instantiate
+
+ private static final Access IMPL_TOKEN = Access.getToken();
++ private static final MemberName.Factory IMPL_LOOKUP = MemberName.getFactory(IMPL_TOKEN);
+
+ //// Method handle creation from ordinary methods.
+
@@ -2524,6 +4498,8 @@ new file mode 100644
+ * Produce a method handle for a static method.
+ * The type of the method handle will be that of the method.
+ * The method and all its argument types must be accessible to the caller.
++ * If the method's class has not yet been initialized, that is done
++ * immediately, before the method handle is returned.
+ * @param defc the class from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method
@@ -2533,21 +4509,30 @@ new file mode 100644
+ */
+ public static
+ MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, null, type, false, callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, caller);
++ checkStatic(true, method, caller);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, caller);
++ }
++
++ private static void checkStatic(boolean wantStatic, MemberName m, Class<?> caller) {
++ if (wantStatic != m.isStatic()) {
++ String message = wantStatic ? "expected a static method" : "expected a non-static method";
++ throw newNoAccessException(message, m, caller);
++ }
+ }
+
+ /**
+ * Produce a method handle for a virtual method.
+ * The type of the method handle will be that of the method,
-+ * with the receiver type (<code>defc</code>) prepended.
++ * with the receiver type ({@code defc}) prepended.
+ * The method and all its argument types must be accessible to the caller.
+ * <p>
+ * When called, the handle will treat the first argument as a receiver
+ * and dispatch on the receiver's type to determine which method
+ * implementation to enter.
+ * (The dispatching action is identical with that performed by an
-+ * <code>invokevirtual</code> or <code>invokeinterface</code> instruction.)
++ * {@code invokevirtual} or {@code invokeinterface} instruction.)
+ * @param defc the class or interface from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
@@ -2557,46 +4542,63 @@ new file mode 100644
+ */
+ public static
+ MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, defc, type, true, callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type), true, caller);
++ checkStatic(false, method, caller);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, caller);
+ }
+
+ /**
+ * Produce an early-bound method handle for a virtual method,
-+ * or a handle for a constructor.
++ * or a handle for a constructor, as if called from an {@code invokespecial}
++ * instruction from {@code caller}.
+ * The type of the method handle will be that of the method or constructor,
-+ * with the receiver type (<code>defc</code>) prepended.
++ * with a suitably restricted receiver type (such as {@code caller}) prepended.
+ * The method or constructor and all its argument types must be accessible
-+ * to the caller, according to the rules of the
-+ * <code>invokespecial</code> instruction.
++ * to the caller.
+ * <p>
+ * When called, the handle will treat the first argument as a receiver,
+ * but will not dispatch on the receiver's type.
+ * (This direct invocation action is identical with that performed by an
-+ * <code>invokespecial</code> instruction.)
++ * {@code invokespecial} instruction.)
++ * <p>
++ * If the explicitly specified caller class is not identical with the actual
++ * caller of {@code findSpecial}, a security check TBD is performed.
+ * @param defc the class or interface from which the method is accessed
+ * @param name the name of the method, or "<init>" for a constructor
+ * @param type the type of the method, with the receiver argument omitted
++ * @param specialCaller the proposed calling class to perform the {@code invokespecial}
+ * @return the desired method handle, 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);
++ MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
++ Class<?> specialCaller) throws NoAccessException {
++ Class<?> caller = Reflection.getCallerClass(2);
++ checkSpecialCaller(specialCaller, caller);
++ MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
++ checkStatic(false, method, caller);
++ if (name.equals("<init>")) {
++ if (defc != specialCaller)
++ throw newNoAccessException("constructor must be local to caller", method, caller);
++ } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
++ throw newNoAccessException("method must be in a superclass of caller", method, caller);
++ }
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
+ }
+
+ /**
+ * Produce an early-bound method handle for a non-static method.
++ * The receiver must have a supertype {@code defc} in which a method
++ * of the given name and type is accessible to the caller.
++ * The method and all its argument types must be accessible to the caller.
+ * 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:
++ * Equivalent to the following expression:
+ * <code>
-+ * {@link #insertArgument}({@link #findVirtual}(receiver.getClass(), name, type), receiver)
++ * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
+ * </code>
+ * @param receiver the object from which the method is accessed
+ * @param name the name of the method
@@ -2607,10 +4609,16 @@ new file mode 100644
+ */
+ public static
+ MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ Class<?> defc = receiver.getClass();
-+ MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, defc, name, defc, type, true, callc);
-+ return insertArgument(dmh, receiver);
++ Class<?> caller = Reflection.getCallerClass(2);
++ Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
++ MemberName reference = new MemberName(rcvc, name, type);
++ MemberName method = IMPL_LOOKUP.resolveOrFail(reference, true, caller);
++ checkStatic(false, method, caller);
++ MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, caller);
++ MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
++ if (bmh == null)
++ throw newNoAccessException(method, caller);
++ return bmh;
+ }
+
+ /**
@@ -2620,7 +4628,7 @@ new file mode 100644
+ * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
+ * The type of the method handle will be that of the method,
+ * with the receiver type prepended (but only if it is non-static).
-+ * If the method's <code>accessible</code> flag is not set,
++ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the caller.
+ * If <i>m</i> is not public, do not share the resulting handle with untrusted callers.
+ * @param m the reflected method
@@ -2629,27 +4637,86 @@ new file mode 100644
+ */
+ public static
+ MethodHandle unreflect(Method m) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.findMethod(IMPL_TOKEN, m, true, callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ return unreflect(new MemberName(m), m.isAccessible(), true, caller);
+ }
+
+ /**
+ * Produce a method handle for a reflected method.
+ * It will bypass checks for overriding methods on the receiver,
-+ * as if by the <code>invokespecial</code> instruction.
++ * as if by the {@code invokespecial} instruction.
+ * The type of the method handle will be that of the method,
+ * with the receiver type prepended.
-+ * If the method's <code>accessible</code> flag is not set,
++ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the caller,
-+ * as if <code>invokespecial</code> instruction were being linked.
++ * as if {@code invokespecial} instruction were being linked.
+ * @param m the reflected method
+ * @return a method handle which can invoke the reflected method
+ * @exception NoAccessException if access checking fails
+ */
+ public static
-+ MethodHandle unreflectSpecial(Method m) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.findMethod(IMPL_TOKEN, m, false, callc);
++ MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
++ Class<?> caller = Reflection.getCallerClass(2);
++ checkSpecialCaller(specialCaller, caller);
++ MemberName mname = new MemberName(m);
++ checkStatic(false, mname, caller);
++ return unreflect(mname, m.isAccessible(), false, specialCaller);
++ }
++
++// /**
++// * Produce a method handle for a reflected constructor.
++// * It will allow direct access to the constructor,
++// * as if by the {@code invokespecial} instruction.
++// * The type of the method handle will be that of the method,
++// * with the receiver type prepended.
++// * If the constructor's {@code accessible} flag is not set,
++// * access checking is performed immediately on behalf of the caller,
++// * as if {@code invokespecial} instruction were being linked.
++// * @param ctor the reflected constructor
++// * @param specialCaller the proposed calling class to perform the {@code invokespecial}
++// * @return a method handle which can invoke the reflected constructor
++// * @exception NoAccessException if access checking fails
++// */
++// public static
++// MethodHandle unreflectSpecial(Constructor ctor, Class<?> specialCaller) throws NoAccessException {
++// Class<?> caller = Reflection.getCallerClass(2);
++// checkSpecialCaller(specialCaller, caller);
++// MemberName m = new MemberName(ctor);
++// checkStatic(false, m, caller);
++// return unreflect(m, ctor.isAccessible(), false, specialCaller);
++// }
++
++ private static
++ void checkSpecialCaller(Class<?> specialCaller, Class<?> caller) {
++ if (caller != null && !VerifyAccess.isSamePackageMember(specialCaller, caller))
++ throw newNoAccessException("no private access", new MemberName(specialCaller), caller);
++ }
++
++ // Helper for creating handles on reflected methods and constructors.
++ private static
++ MethodHandle unreflect(MemberName m, boolean isAccessible, boolean doDispatch, Class<?> caller) {
++ MethodType mtype = m.getInvocationType();
++ Class<?> defc = m.getDeclaringClass();
++ int mods = m.getModifiers();
++ if (m.isStatic()) {
++ if (!isAccessible &&
++ VerifyAccess.isAccessible(defc, mods, false, caller) == null)
++ throw newNoAccessException(m, caller);
++ } else {
++ Class<?> constraint;
++ if (isAccessible) {
++ // abbreviated access check for "unlocked" method
++ constraint = doDispatch ? defc : caller;
++ } else {
++ constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, caller);
++ }
++ if (constraint != defc && !constraint.isAssignableFrom(defc)) {
++ if (!defc.isAssignableFrom(constraint))
++ throw newNoAccessException("receiver must be in caller class", m, caller);
++ mtype = mtype.changeParameterType(0, constraint);
++ }
++ }
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, caller);
+ }
+
+ /**
@@ -2658,7 +4725,7 @@ new file mode 100644
+ * The type of the method handle will have a return type of the field's
+ * value type. Its sole argument will be the field's containing class
+ * (but only if it is non-static).
-+ * If the method's <code>accessible</code> flag is not set,
++ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the caller.
+ * @param f the reflected field
+ * @return a method handle which can load values from the reflected field
@@ -2666,8 +4733,8 @@ new file mode 100644
+ */
+ public static
+ MethodHandle unreflectGetter(Field f) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.accessField(IMPL_TOKEN, f, false, (Class)callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, (Class)caller);
+ }
+
+ /**
@@ -2677,7 +4744,7 @@ new file mode 100644
+ * Its last argument will be the field's value type.
+ * Its other argument will be the field's containing class
+ * (but only if it is non-static).
-+ * If the method's <code>accessible</code> flag is not set,
++ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the caller.
+ * @param f the reflected field
+ * @return a method handle which can store values into the reflected field
@@ -2685,8 +4752,8 @@ new file mode 100644
+ */
+ public static
+ MethodHandle unreflectSetter(Field f) throws NoAccessException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.accessField(IMPL_TOKEN, f, true, (Class)callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, (Class)caller);
+ }
+
+ /**
@@ -2701,8 +4768,8 @@ new file mode 100644
+ */
+ public static
+ MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
-+ Class<?> callc = Reflection.getCallerClass(2);
-+ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false, (Class)callc);
++ Class<?> caller = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false, (Class)caller);
+ }
+
+ /**
@@ -2716,12 +4783,46 @@ new file mode 100644
+ */
+ 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)
++ Class<?> caller = Reflection.getCallerClass(2);
++ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true, (Class)caller);
++ }
++
++
++ /// method handle invocation (reflective style)
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Call the {@code invoke} method of a given method handle.
++ * The given arguments must exactly match the parameter types of the method handle.
++ * <em>TBD: Fill in the details.</em>
++ * No conversions are performed except reference casting and unboxing of primitives.
++ * @param target method handle to invoke
++ * @param arguments arguments to pass to the target (with any primitives wrapped)
++ * @return the result of the method (with any primitive wrapped)
++ */
++ public static
++ Object invoke(MethodHandle target, Object... arguments) {
++ // TO DO: Remove this checking logic; must be part of the invoker anyway.
++ int length = arguments.length;
++ MethodType type = target.type();
++ if (type.parameterCount() != length)
++ throw new WrongMethodTypeException("wrong number of arguments");
++ for (int i = 0; i < length; i++) {
++ Object argument = arguments[i];
++ Class<?> ptype = type.parameterType(i);
++ if (ptype.isPrimitive()) {
++ argument.getClass(); // provoke NPE if null
++ ptype = Wrappers.asWrapperType(ptype);
++ } else if (ptype.isInterface()) {
++ ptype = Object.class; // no check
++ }
++ if (ptype != Object.class) {
++ ptype.cast(argument);
++ }
++ }
++ // End of checking logic.
++ return MethodHandleInvoker.make(target.type()).invoke(target, arguments);
++ }
+
+ /**
+ * <em>WORK IN PROGRESS:</em>
@@ -2816,6 +4917,8 @@ new file mode 100644
+ return checkValue(T0, T1, value);
+ }
+
++ /// method handle modification (creation from other method handles)
++
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which adapts the type of the
@@ -2826,7 +4929,7 @@ new file mode 100644
+ * The resulting method handle is guaranteed to confess a type
+ * which is equal to the desired new type, with any varargs property erased.
+ * <p>
-+ * If the original type and new type are equal, returns mh.
++ * If the original type and new type are equal, returns target.
+ * <p>
+ * The following conversions are applied as needed both to
+ * arguments and return types. Let T0 and T1 be the differing
@@ -2878,19 +4981,53 @@ new file mode 100644
+ * <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 target the method handle to invoke after arguments are retyped
+ * @param newType the expected type of the new method handle
-+ * @return a method handle which delegates to {@code mh} after performing
++ * @return a method handle which delegates to {@code target} 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();
++ MethodHandle convertArguments(MethodHandle target, MethodType newType) {
++ MethodType oldType = target.type();
+ if (oldType.equals(newType))
-+ return mh;
-+ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh,
-+ newType, mh.type());
++ return target;
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
++ newType, target.type(), null);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle which adapts the calling sequence of the
++ * given method handle to a new type, by reordering the arguments.
++ * Duplication and omission is allowed.
++ * The resulting method handle is guaranteed to confess a type
++ * which is equal to the desired new type.
++ * <p>
++ * The given permutation string controls the reordering.
++ * The characters of the string are treated as small integers.
++ * All the characters must be in the range zero (i.e., '\0') to
++ * the number of incoming arguments (the parameter count of the new type).
++ * The length of the string must be equal to the number of outgoing
++ * parameters (the parameter count of the original method handle's type).
++ * If the n-th character of the string denotes the integer k,
++ * then the n-th incoming argument becomes the k-th outgoing argument.
++ * <p>
++ * Pairwise conversions are applied as needed to arguments and return
++ * values, as with {@link #convertArguments}.
++ * @param target the method handle to invoke after arguments are reordered
++ * @param newType the expected type of the new method handle
++ * @param permutation a string which controls the reordering
++ * @return a method handle which delegates to {@code target} after performing
++ * any necessary argument motion and conversions, and arranges for any
++ * necessary return value conversions
++ */
++ public static
++ MethodHandle permuteArguments(MethodHandle target, MethodType newType, String permutation) {
++ MethodType oldType = target.type();
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
++ newType, target.type(),
++ permutation);
+ }
+
+ /**
@@ -2917,14 +5054,14 @@ new file mode 100644
+ * arguments in the old type over the ordinary arguments in the new type.
+ * If there are no excess arguments, the spread argument is also
+ * allowed to be null.
-+ * @param mh the method handle to invoke after the argument is prepended
++ * @param target the method handle to invoke after the argument is prepended
+ * @param newType the expected type of the new method handle
+ * @return a new method handle which spreads its final argument,
+ * before calling the original method handle
+ */
+ public static
-+ MethodHandle spreadArguments(MethodHandle mh, MethodType newType) {
-+ MethodType oldType = mh.type();
++ MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
++ MethodType oldType = target.type();
+ int inargs = newType.parameterCount();
+ int outargs = oldType.parameterCount();
+ int spreadPos = inargs - 1;
@@ -2932,7 +5069,7 @@ new file mode 100644
+ if (spreadPos < 0 || numSpread < 0)
+ throw newIllegalArgumentException("wrong number of arguments");
+ newType = newType.changeVarArgs(true);
-+ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, newType, oldType);
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, newType, oldType, null);
+ }
+
+ /**
@@ -2949,14 +5086,14 @@ new file mode 100644
+ * The trailing arguments of the new type which correspond to
+ * the spread argument are all converted to type T and collected
+ * into an array before the original method is called.
-+ * @param mh the method handle to invoke after the argument is prepended
++ * @param target the method handle to invoke after the argument is prepended
+ * @param newType the expected type of the new method handle
+ * @return a new method handle which collects some trailings argument
+ * into an array, before calling the original method handle
+ */
+ public static
-+ MethodHandle collectArguments(MethodHandle mh, MethodType newType) {
-+ MethodType oldType = mh.type();
++ MethodHandle collectArguments(MethodHandle target, MethodType newType) {
++ MethodType oldType = target.type();
+ int inargs = newType.parameterCount();
+ int outargs = oldType.parameterCount();
+ int collectPos = outargs - 1;
@@ -2964,7 +5101,7 @@ new file mode 100644
+ if (collectPos < 0 || numCollect < 0)
+ throw newIllegalArgumentException("wrong number of arguments");
+ oldType = oldType.changeVarArgs(true);
-+ return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, newType, oldType);
++ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, newType, oldType, null);
+ }
+
+ /**
@@ -2974,11 +5111,11 @@ new file mode 100644
+ * The type of the new method handle will drop the first argument
+ * type from the original handle's type.
+ * <p>
-+ * Equivalent to <code>insertArgument(mh, value, 0)</code>.
++ * Equivalent to {@code insertArgument(target, value, 0)}.
+ */
+ public static
-+ MethodHandle insertArgument(MethodHandle mh, Object value) {
-+ return insertArgument(mh, value, 0);
++ MethodHandle insertArgument(MethodHandle target, Object value) {
++ return insertArgument(target, value, 0);
+ }
+
+ /**
@@ -2988,12 +5125,12 @@ new file mode 100644
+ * The type of the new method handle will drop the last argument
+ * type from the original handle's type.
+ * <p>
-+ * Equivalent to <code>insertArgument(mh, value, N)</code>,
-+ * where <i>N</i> is the number of arguments to <i>mh</i>.
++ * Equivalent to {@code insertArgument(target, value, N)},
++ * where <i>N</i> is the number of arguments to <i>target</i>.
+ */
+ public static
-+ MethodHandle appendArgument(MethodHandle mh, Object value) {
-+ return insertArgument(mh, value, mh.type().parameterCount());
++ MethodHandle appendArgument(MethodHandle target, Object value) {
++ return insertArgument(target, value, target.type().parameterCount());
+ }
+
+ /**
@@ -3008,18 +5145,18 @@ new file mode 100644
+ * must be a wrapper, and is unboxed to produce the primitive.
+ * <p>
+ * The <i>pos</i> may range between zero and <i>N</i> (inclusively),
-+ * where <i>N</i> is the number of argument types in <i>mh</i>,
++ * where <i>N</i> is the number of argument types in <i>target</i>,
+ * meaning to insert the new argument as the first or last (respectively),
+ * or somewhere in between.
-+ * @param mh the method handle to invoke after the argument is inserted
++ * @param target the method handle to invoke after the argument is inserted
+ * @param value the argument to insert
+ * @param pos where to insert the argument (zero for the first)
+ * @return a new method handle which inserts an additional argument,
+ * before calling the original method handle
+ */
+ public static
-+ MethodHandle insertArgument(MethodHandle mh, Object value, int pos) {
-+ MethodType oldType = mh.type();
++ MethodHandle insertArgument(MethodHandle target, Object value, int pos) {
++ MethodType oldType = target.type();
+ ArrayList<Class<?>> ptypes =
+ new ArrayList<Class<?>>(oldType.parameterList());
+ int outargs = oldType.parameterCount();
@@ -3032,11 +5169,11 @@ new file mode 100644
+ // At least for now, make bound method handles a special case.
+ // This lets us get by with minimal JVM support, at the expense
+ // of generating signature-specific adapters as Java bytecodes.
-+ MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, mh, value);
++ MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
+ if (bmh != null) return bmh;
+ // else fall through to general adapter machinery
+ }
-+ return MethodHandleImpl.bindArgument(IMPL_TOKEN, mh, pos, value);
++ return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
+ }
+
+ /**
@@ -3047,19 +5184,19 @@ new file mode 100644
+ * 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>,
++ * where <i>N</i> is the number of argument types in <i>target</i>,
+ * meaning to drop the first or last argument (respectively),
+ * or an argument somewhere in between.
-+ * @param mh the method handle to invoke after the argument is dropped
++ * @param target the method handle to invoke after the argument is dropped
+ * @param valueTypes the type(s) of the argument to drop
+ * @param pos which argument to drop (zero for the first)
+ * @return a new method handle which drops an argument of the given type,
+ * before calling the original method handle
+ */
+ public static
-+ MethodHandle dropArguments(MethodHandle mh, int pos, Class<?>... valueTypes) {
-+ if (valueTypes.length == 0) return mh;
-+ MethodType oldType = mh.type();
++ MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
++ if (valueTypes.length == 0) return target;
++ MethodType oldType = target.type();
+ int outargs = oldType.parameterCount();
+ int inargs = outargs + valueTypes.length;
+ if (pos < 0 || pos >= inargs)
@@ -3068,7 +5205,7 @@ new file mode 100644
+ new ArrayList<Class<?>>(oldType.parameterList());
+ ptypes.addAll(pos, Arrays.asList(valueTypes));
+ MethodType newType = MethodType.make(oldType.returnType(), ptypes);
-+ return MethodHandleImpl.dropArguments(IMPL_TOKEN, mh, newType, pos);
++ return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
+ }
+
+ /**
@@ -3079,6 +5216,19 @@ new file mode 100644
+ * All three method handles must have the same corresponding
+ * argument and return types, except that the return type
+ * of the test must be boolean.
++ * <p> Here is pseudocode for the resulting adapter:
++ * <blockquote><pre>
++ * signature T(A...);
++ * boolean test(A...);
++ * T target(A...);
++ * T fallback(A...);
++ * T adapter(A... a) {
++ * if (test(a...))
++ * return target(a...);
++ * else
++ * return fallback(a...);
++ * }
++ * </pre></blockquote>
+ * @param test method handle used for test, must return boolean
+ * @param target method handle to call if test passes
+ * @param fallback method handle to call if test fails
@@ -3095,36 +5245,81 @@ new file mode 100644
+ throw newIllegalArgumentException("target and fallback types do not match");
+ if (target.type().changeReturnType(boolean.class) != test.type())
+ throw newIllegalArgumentException("target and test types do not match");
++ /* {
++ MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
++ return z ? t : f;
++ }
++ MethodHandle choose = findVirtual(MethodHandles.class, "choose",
++ MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
++ choose = appendArgument(choose, target);
++ choose = appendArgument(choose, fallback);
++ choose = combineArguments(choose, test);
++ MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
++ return checkArguments(invoke, choose, 0);
++ } */
+ 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
++ * Adapt a target method handle {@code target} by first checking its arguments,
++ * and then calling the target.
++ * The check is performed by a second method handle, the {@code checker}.
++ * After this, control passes to the target method handle, with the same
++ * arguments.
++ * <p>
++ * The return value of the checker is inserted into the argument list
++ * for {@code target} at the indicated position {@code pos}, if it is non-negative.
++ * Except for this inserted argument (if any), the argument types of
++ * the target {@code target} and the {@code checker} must be identical.
++ * <p>
++ * The checker handle must have the same argument types as the
++ * target handle, but must return {@link MethodHandle} instead of
+ * the ultimate return type. The returned method handle, in turn,
+ * is required to have exactly the given final method type.
-+ * @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
++ * <p> Here is pseudocode for the resulting adapter:
++ * <blockquote><pre>
++ * signature V(A[pos]..., B...);
++ * signature T(A[pos]..., V, B...);
++ * T target(A... a, V, B... b);
++ * U checker(A..., B...);
++ * T adapter(A... a, B... b) {
++ * V v = checker(a..., b...);
++ * return target(a..., v, b...);
++ * }
++ * </pre></blockquote>
++ * @param target the method handle to invoke after arguments are checked
++ * @param checker method handle to call initially on the incoming arguments
++ * @param pos where the return value of {@code checker} is to
++ * be inserted as an argument to {@code target}
+ * @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}
++ * @throws IllegalArgumentException if {@code checker} does not itself
++ * return either void or the {@code pos}-th argument of {@code target},
++ * or does not have the same argument types as {@code target}
++ * (minus the inserted argument)
+ */
+ public static
-+ MethodHandle 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);
-+ }
-+
++ MethodHandle checkArguments(MethodHandle target, MethodHandle checker, int pos) {
++ MethodType mhType = target.type();
++ Class<?> checkType = checker.type().returnType();
++ MethodType incomingArgs;
++ if (pos < 0) {
++ // No inserted argument; target & checker must have same argument types.
++ incomingArgs = mhType;
++ if (!incomingArgs.changeReturnType(checkType).equals(checker.type()))
++ throw newIllegalArgumentException("target and checker types do not match");
++ } else {
++ // Inserted argument.
++ if (pos >= mhType.parameterCount()
++ || mhType.parameterType(pos) != checkType)
++ throw newIllegalArgumentException("inserted checker argument does not match target");
++ incomingArgs = mhType.deleteParameterType(pos);
++ }
++ if (!incomingArgs.changeReturnType(checkType).equals(checker.type())) {
++ throw newIllegalArgumentException("target and checker types do not match");
++ }
++ return MethodHandleImpl.checkArguments(IMPL_TOKEN, target, checker, pos);
++ }
+
+ /// standard method handles
+
@@ -3177,9 +5372,9 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/MethodType.java
-@@ -0,0 +1,640 @@
+@@ -0,0 +1,579 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -3205,15 +5400,13 @@ 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;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import impl.java.dyn.*;
++import impl.java.dyn.util.Signatures;
++import static impl.java.dyn.MemberName.newIllegalArgumentException;
+
+/**
+ * Run-time token used to match call sites with method handles.
@@ -3237,20 +5430,32 @@ new file mode 100644
+ private static final Access IMPL_TOKEN = Access.getToken();
+
+ private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean varargs) {
++ checkRtype(rtype);
++ checkPtypes(ptypes);
+ this.rtype = rtype;
+ this.ptypes = ptypes;
+ if (!varargs) {
+ this.form = MethodTypeForm.FAKE[0];
+ } else {
+ this.form = MethodTypeForm.FAKE[1];
-+ checkVarargs();
++ checkVarargs(ptypes);
+ }
+ assert(this.isVarArgs() == varargs);
+ }
+
-+ private void checkVarargs() {
++ private void checkRtype(Class<?> rtype) {
++ rtype.equals(rtype); // null check
++ }
++ private void checkPtypes(Class<?>[] ptypes) {
++ for (Class<?> ptype : ptypes) {
++ ptype.equals(ptype); // null check
++ if (ptype == void.class)
++ throw newIllegalArgumentException("void parameter: "+this);
++ }
++ }
++ private void checkVarargs(Class<?>[] ptypes) {
+ if (ptypes.length == 0 || !ptypes[ptypes.length-1].isArray())
-+ throw new IllegalArgumentException("not varargs: "+this);
++ throw newIllegalArgumentException("not varargs: "+this);
+ }
+
+ static final HashMap<MethodType,MethodType> internTable
@@ -3262,6 +5467,8 @@ new file mode 100644
+ * @param rtype the return type
+ * @param ptypes the parameter types
+ * @return the interned method type with the given parts
++ * @throws NullPointerException if rtype or any ptype is null
++ * @throws IllegalArgumentException if any of the ptypes is void,
+ */
+ public static
+ MethodType make(Class<?> rtype, Class<?>[] ptypes) {
@@ -3273,7 +5480,9 @@ new file mode 100644
+ * @param ptypes the parameter types
+ * @param varargs whether the method type will be varargs
+ * @return the interned method type with the given parts
-+ * @throws IllegalArgumentException if varargs is true and the last parameter type is not an array
++ * @throws NullPointerException if rtype or any ptype is null
++ * @throws IllegalArgumentException if any of the ptypes is void,
++ * or if varargs is true and the last parameter type is not an array
+ */
+ public static
+ MethodType make(Class<?> rtype, Class<?>[] ptypes, boolean varargs) {
@@ -3286,10 +5495,15 @@ new file mode 100644
+ 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[])}.
++ * The leading parameter type is prepended to the remaining array.
++ */
+ public static
+ MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
-+ return makeImpl(rtype, append(ptype0, ptypes), false, false);
++ Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
++ ptypes1[0] = ptype0;
++ System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
++ return makeImpl(rtype, ptypes1, false, true);
+ }
+
+ /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
@@ -3327,6 +5541,9 @@ new file mode 100644
+ */
+ static
+ MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean varargs, boolean trusted) {
++ if (ptypes == null || ptypes.length == 0) {
++ ptypes = NO_PTYPES; trusted = true;
++ }
+ MethodType mt1 = new MethodType(rtype, ptypes, varargs);
+ MethodType mt0;
+ synchronized (internTable) {
@@ -3339,10 +5556,8 @@ new file mode 100644
+ 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);
-+ }
++ if (mt1.form.erasedType == mt1)
++ MethodHandleImpl.init(IMPL_TOKEN, mt1);
+ assert(mt1.isVarArgs() == varargs);
+ synchronized (internTable) {
+ mt0 = internTable.get(mt1);
@@ -3387,27 +5602,6 @@ new file mode 100644
+ 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)}.
@@ -3741,90 +5935,30 @@ new file mode 100644
+ public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
+ throws IllegalArgumentException, TypeNotPresentException
+ {
-+ if (loader == null)
-+ loader = ClassLoader.getSystemClassLoader();
-+ String str = bytecodeSignature;
-+ int[] i = {0};
-+ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
-+ if (i[0] < str.length() && str.charAt(i[0]) == '(') {
-+ ++i[0]; // skip '('
-+ while (i[0] < str.length() && str.charAt(i[0]) != ')') {
-+ Class<?> pt = parseSig(str, i, loader);
-+ if (pt == null || pt == void.class)
-+ parseError(str, "bad argument type");
-+ ptypes.add(pt);
-+ }
-+ ++i[0]; // skip ')'
-+ }
-+ Class<?> rtype = parseSig(str, i, loader);
-+ if (rtype == null || i[0] != str.length())
-+ parseError(str, "bad return type");
-+ return make(rtype, ptypes);
-+ }
-+
-+ /** Create a bytecode signature representation of the type.
-+ * Note that this is not a strict inverse of
++ List<Class<?>> types = Signatures.parseMethod(bytecodeSignature, loader);
++ Class<?> rtype = types.remove(types.size() - 1);
++ Class<?>[] ptypes = types.toArray(NO_PTYPES);
++ return makeImpl(rtype, ptypes, false, true);
++ }
++
++ /**
++ * 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() {
-+ StringBuilder sb = new StringBuilder();
-+ sb.append('(');
-+ for (Class<?> pt : ptypes)
-+ unparseSig(pt, sb);
-+ sb.append(')');
-+ unparseSig(rtype, sb);
-+ return sb.toString();
-+ }
-+
-+ static private void parseError(String str, String msg) {
-+ throw new IllegalArgumentException("bad signature: "+str+": "+msg);
-+ }
-+
-+ static private Class<?> parseSig(String str, int[] i, ClassLoader loader) {
-+ if (i[0] == str.length()) return null;
-+ char c = str.charAt(i[0]++);
-+ if (c == 'L') {
-+ int beg = i[0], end = str.indexOf(';', beg);
-+ if (end < 0) return null;
-+ i[0] = end+1;
-+ String name = str.substring(beg, end).replace('/', '.');
-+ try {
-+ return loader.loadClass(name);
-+ } catch (ClassNotFoundException ex) {
-+ throw new TypeNotPresentException(name, ex);
-+ }
-+ } else if (c == '[') {
-+ Class<?> t = parseSig(str, i, loader);
-+ if (t != null)
-+ t = java.lang.reflect.Array.newInstance(t, 0).getClass();
-+ return t;
-+ } else {
-+ return Wrappers.basicTypeFromChar(c);
-+ }
-+ }
-+
-+ private void unparseSig(Class<?> t, StringBuilder sb) {
-+ char c = Wrappers.basicTypeChar(t);
-+ if (c != 'L') {
-+ sb.append(c);
-+ } else {
-+ boolean lsemi = (!t.isArray());
-+ if (lsemi) sb.append('L');
-+ sb.append(t.getName().replace('.', '/'));
-+ if (lsemi) sb.append(';');
-+ }
-+ }
-+
++ return Signatures.unparse(this);
++ }
+}
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,271 @@
+@@ -0,0 +1,270 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -3871,8 +6005,8 @@ new file mode 100644
+ final long primCounts; // packed prim & double counts
+ final boolean varargs; // is this a "..." type?
+ final int vmslots; // total number of parameter slots
-+ final MethodType erasedType; // the canonical erasure
-+ final MethodType wrappedType; // erasure, with primitives wrapped
++ final MethodType erasedType; // the canonical erasure
++ final MethodType wrappedType; // erasure, with primitives wrapped
+
+ public static MethodTypeForm of(MethodType type) {
+ return type.form;
@@ -4092,15 +6226,14 @@ new file mode 100644
+ }
+ return cs;
+ }
-+
+}
-diff --git a/src/share/classes/java/dyn/WrongMethodTypeException.java b/src/share/classes/java/dyn/WrongMethodTypeException.java
+diff --git a/src/share/classes/java/dyn/NoAccessException.java b/src/share/classes/java/dyn/NoAccessException.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/java/dyn/WrongMethodTypeException.java
-@@ -0,0 +1,59 @@
++++ b/src/share/classes/java/dyn/NoAccessException.java
+@@ -0,0 +1,75 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -4127,6 +6260,86 @@ new file mode 100644
+package java.dyn;
+
+/**
++ * Thrown to indicate that a caller has attempted to create a method handle
++ * which calls a method to which the caller does not have access.
++ * This unchecked exception is analogous to {@link IllegalAccessException},
++ * which is a checked exception thrown when reflective invocation fails
++ * because of an access check. With method handles, this same access
++ * checking is performed on behalf of the method handle creator,
++ * at the time of creation.
++ * @author John Rose, JSR 292 EG
++ */
++public class NoAccessException extends RuntimeException {
++ /**
++ * Constructs a {@code NoAccessException} with no detail message.
++ */
++ public NoAccessException() {
++ super();
++ }
++
++ /**
++ * Constructs a {@code NoAccessException} with the specified
++ * detail message.
++ *
++ * @param s the detail message
++ */
++ public NoAccessException(String s) {
++ super(s);
++ }
++
++ /**
++ * Constructs a {@code NoAccessException} with the specified cause.
++ *
++ * @param cause the underlying cause of the exception
++ */
++ public NoAccessException(Throwable cause) {
++ super(cause);
++ }
++
++ /**
++ * Constructs a {@code NoAccessException} with the specified
++ * detail message and cause.
++ *
++ * @param s the detail message
++ * @param cause the underlying cause of the exception
++ */
++ public NoAccessException(String s, Throwable cause) {
++ super(s, cause);
++ }
++}
+diff --git a/src/share/classes/java/dyn/WrongMethodTypeException.java b/src/share/classes/java/dyn/WrongMethodTypeException.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/WrongMethodTypeException.java
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package java.dyn;
++
++/**
+ * Thrown to indicate that code has attempted to call a method handle
+ * via the wrong method type. As with the bytecode representation of
+ * normal Java method calls, method handle calls are strongly typed
@@ -4158,78 +6371,13 @@ new file mode 100644
+ super(s);
+ }
+}
-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/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.
-+ *
-+ * 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.*;
-+
-+/**
-+ * The CallSite privately created by the JVM at every invokedynamic instruction.
-+ * @author jrose
-+ */
-+class DynCallSite extends CallSite {
-+ // Fields used only by the JVM. Do not use or change.
-+ Object vmref;
-+ long vmdata;
-+
-+ 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
-+ 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/package-info.java b/src/share/classes/java/dyn/package-info.java
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/package-info.java
@@ -0,0 +1,32 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
--- a/series Thu Jan 29 13:53:27 2009 -0800
+++ b/series Thu Jan 29 13:54:01 2009 -0800
@@ -1,6 +1,6 @@
# base = d8eb2738db6b in http://hg.openjdk.java.net/jdk7/hotspot/jdk
anonk.patch #-/anonk #+d8eb2738db6b #+jdk7-b44
-meth.patch #-/meth #+jdk7-b43
-indy.patch #-/indy #+jdk7-b34
+meth.patch #-/meth #+d8eb2738db6b #+jdk7-b44
+indy.patch #-/indy #+jdk7-b34 #-testable
#inti.patch #-/inti #+jdk7-b34 #-buildable
callcc.patch #-/callcc #+jdk7-b30 #-testable