--- a/indy.patch Tue Jun 02 23:42:20 2009 -0700
+++ b/indy.patch Thu Jun 04 21:28:20 2009 -0700
@@ -226,7 +226,24 @@ diff --git a/src/share/classes/java/dyn/
diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java
--- a/src/share/classes/java/dyn/MethodHandles.java
+++ b/src/share/classes/java/dyn/MethodHandles.java
-@@ -135,10 +135,30 @@
+@@ -36,6 +36,8 @@
+ import java.lang.reflect.Modifier;
+ import java.util.ArrayList;
+ import java.util.Arrays;
++import java.util.Iterator;
++import java.util.List;
+ import sun.dyn.Invokers;
+ import sun.dyn.MethodTypeImpl;
+ import sun.reflect.Reflection;
+@@ -53,7 +55,6 @@
+ * Generics are not variadic, and so cannot represent this.</li>
+ * <li>Method types can specify arguments of primitive types,
+ * which Java generic types cannot range over.</li>
+- * <li>Method types can optionally specify varargs (ellipsis).</li>
+ * </ol>
+ * @author John Rose, JSR 292 EG
+ */
+@@ -135,10 +136,30 @@
* an access$N method.
*/
Lookup() {
@@ -261,7 +278,7 @@ diff --git a/src/share/classes/java/dyn/
}
private Lookup(Class<?> lookupClass) {
-@@ -184,6 +204,9 @@
+@@ -184,6 +205,9 @@
/**
* Produce a method handle for a static method.
* The type of the method handle will be that of the method.
@@ -271,7 +288,7 @@ diff --git a/src/share/classes/java/dyn/
* The method and all its argument types must be accessible to the lookup class.
* If the method's class has not yet been initialized, that is done
* immediately, before the method handle is returned.
-@@ -196,10 +219,11 @@
+@@ -196,10 +220,11 @@
*/
public
MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
@@ -286,7 +303,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -228,9 +252,10 @@
+@@ -228,9 +253,10 @@
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
@@ -300,7 +317,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -259,15 +284,17 @@
+@@ -259,15 +285,17 @@
*/
public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
Class<?> specialCaller) throws NoAccessException {
@@ -323,7 +340,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -275,13 +302,19 @@
+@@ -275,13 +303,19 @@
* The receiver must have a supertype {@code defc} in which a method
* of the given name and type is accessible to the lookup class.
* The method and all its argument types must be accessible to the lookup class.
@@ -346,7 +363,7 @@ diff --git a/src/share/classes/java/dyn/
* @param receiver the object from which the method is accessed
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
-@@ -292,16 +325,18 @@
+@@ -292,16 +326,18 @@
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
MemberName reference = new MemberName(rcvc, name, type);
@@ -369,7 +386,7 @@ diff --git a/src/share/classes/java/dyn/
* Make a direct method handle to <i>m</i>, if the lookup class has permission.
* If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
* If <i>m</i> is virtual, overriding is respected on every call.
-@@ -316,10 +351,11 @@
+@@ -316,10 +352,11 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflect(Method m) throws NoAccessException {
@@ -382,7 +399,7 @@ diff --git a/src/share/classes/java/dyn/
* Produce a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
* as if by the {@code invokespecial} instruction.
-@@ -333,37 +369,41 @@
+@@ -333,37 +370,41 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
@@ -433,7 +450,7 @@ diff --git a/src/share/classes/java/dyn/
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
-@@ -371,16 +411,17 @@
+@@ -371,16 +412,17 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectGetter(Field f) throws NoAccessException {
@@ -455,7 +472,7 @@ diff --git a/src/share/classes/java/dyn/
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
-@@ -388,59 +429,60 @@
+@@ -388,59 +430,60 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSetter(Field f) throws NoAccessException {
@@ -535,7 +552,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -515,45 +557,107 @@
+@@ -515,45 +558,107 @@
if (argc <= 4) {
MethodHandle invoker = invokers(type).genericInvoker();
switch (argc) {
@@ -655,7 +672,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -703,26 +807,15 @@
+@@ -703,26 +808,15 @@
* arguments and return types. Let T0 and T1 be the differing
* new and old parameter types (or old and new return types)
* for corresponding values passed by the new and old method types.
@@ -688,7 +705,7 @@ diff --git a/src/share/classes/java/dyn/
* <li>If T0 and T1 are primitives, then a Java casting
* conversion (JLS 5.5) is applied, if one exists.
* <li>If T0 and T1 are primitives and one is boolean,
-@@ -745,9 +838,9 @@
+@@ -745,9 +839,9 @@
* if necessary to T1 by one of the preceding conversions.
* Otherwise, T0 is converted directly to the wrapper type for T1,
* which is then unboxed.
@@ -701,7 +718,30 @@ diff --git a/src/share/classes/java/dyn/
* </ul>
* @param target the method handle to invoke after arguments are retyped
* @param newType the expected type of the new method handle
-@@ -900,7 +993,7 @@
+@@ -872,20 +966,14 @@
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which adapts the type of the
+ * given method handle to a new type, by collecting a series of
+- * trailing arguments into an array.
+- * The resulting method handle is guaranteed to confess a type
+- * which is equal to the desired new type.
++ * trailing arguments as arguments to a pre-processor method.
+ * <p>
+- * This method is inverse to {@link #spreadArguments}.
++ * This method may be used as an inverse to {@link #spreadArguments}.
+ * The final parameter type of the old type must be an array type T[],
+ * which is the type of what is called the <i>spread</i> argument.
+ * The trailing arguments of the new type which correspond to
+ * the spread argument are all converted to type T and collected
+ * into an array before the original method is called.
+- * <p>
+- * ISSUE: Unify this with combineArguments. CollectArguments
+- * is combineArguments with (a) new Object[]{...} as a combiner,
+- * and (b) the combined arguments dropped, in favor of the combined result.
+ * @param target the method handle to invoke after the argument is prepended
+ * @param newType the expected type of the new method handle
+ * @return a new method handle which collects some trailings argument
+@@ -900,24 +988,27 @@
int numCollect = (inargs - collectPos);
if (collectPos < 0 || numCollect < 0)
throw newIllegalArgumentException("wrong number of arguments");
@@ -710,7 +750,91 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -953,10 +1046,25 @@
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+- * Produce a method handle which calls the original method handle,
+- * after inserting the given argument at the given position.
+- * The type of the new method handle will drop the corresponding argument
+- * type from the original handle's type.
++ * Produce a method handle which calls the original method handle {@code target},
++ * after inserting the given argument(s) at the given position.
++ * The formal parameters to {@code target} which will be supplied by those
++ * arguments are called <em>bound parameters</em>, because the new method
++ * will contain bindings for those parameters take from {@code values}.
++ * The type of the new method handle will drop the types for the bound
++ * parameters from the original target type, since the new method handle
++ * will no longer require those arguments to be supplied by its callers.
+ * <p>
+- * The given argument object must match the dropped argument type.
+- * If the dropped argument type is a primitive, the argument object
+- * must be a wrapper, and is unboxed to produce the primitive.
++ * Each given argument object must match the corresponding bound parameter type.
++ * If a bound parameter type is a primitive, the argument object
++ * must be a wrapper, and will be unboxed to produce the primitive value.
+ * <p>
+ * The <i>pos</i> may range between zero and <i>N</i> (inclusively),
+- * where <i>N</i> is the number of argument types in <i>target</i>,
+- * meaning to insert the new argument as the first or last (respectively),
+- * or somewhere in between.
++ * where <i>N</i> is the number of argument types in resulting method handle
++ * (after bound parameter types are dropped).
+ * @param target the method handle to invoke after the argument is inserted
+ * @param pos where to insert the argument (zero for the first)
+ * @param value the argument to insert
+@@ -925,25 +1016,40 @@
+ * before calling the original method handle
+ */
+ public static
+- MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
++ MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
++ int insCount = values.length;
+ MethodType oldType = target.type();
+ ArrayList<Class<?>> ptypes =
+ new ArrayList<Class<?>>(oldType.parameterList());
+ int outargs = oldType.parameterCount();
+- int inargs = outargs - 1;
+- if (pos < 0 || pos >= outargs)
++ int inargs = outargs - insCount;
++ if (inargs < 0)
++ throw newIllegalArgumentException("too many values to insert");
++ if (pos < 0 || pos > inargs)
+ throw newIllegalArgumentException("no argument type to append");
+- Class<?> valueType = ptypes.remove(pos);
+- value = checkValue(valueType, value);
+- if (pos == 0 && !valueType.isPrimitive()) {
+- // At least for now, make bound method handles a special case.
+- // This lets us get by with minimal JVM support, at the expense
+- // of generating signature-specific adapters as Java bytecodes.
+- MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
+- if (bmh != null) return bmh;
+- // else fall through to general adapter machinery
++ MethodHandle result = target;
++ for (int i = 0; i < insCount; i++) {
++ Object value = values[i];
++ Class<?> valueType = oldType.parameterType(pos+i);
++ value = checkValue(valueType, value);
++ if (pos == 0 && !valueType.isPrimitive()) {
++ // At least for now, make bound method handles a special case.
++ MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value);
++ if (bmh != null) {
++ result = bmh;
++ continue;
++ }
++ // else fall through to general adapter machinery
++ }
++ result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value);
+ }
+- return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
++ return result;
++ }
++
++ @Deprecated
++ public static
++ MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
++ return insertArguments(target, pos, value);
+ }
+
+ /**
+@@ -953,10 +1059,25 @@
* The type of the new method handle will insert the given argument
* type(s), at that position, into the original handle's type.
* <p>
@@ -737,6 +861,174 @@ diff --git a/src/share/classes/java/dyn/
* @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)
+@@ -1040,65 +1161,123 @@
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+- * Adapt a target method handle {@code target} by first processing
+- * its arguments, and then calling the target.
+- * The initial processing is performed by a second method handle, the {@code combiner}.
+- * After this, control passes to the {@code target}, with the same arguments.
++ * Make a method handle which adapts a target method handle,
++ * by running it inside an exception handler.
++ * If the target returns normally, the adapter returns that value.
++ * If an exception matching the specified type is thrown, the fallback
++ * handle is called instead on the exception, plus the original arguments.
+ * <p>
+- * The return value of the {@code combiner} is inserted into the argument list
+- * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
+- * Except for this inserted argument (if any), the argument types of
+- * the target {@code target} and the {@code combiner} must be identical.
++ * The handler must have leading parameter of {@code exType} or a supertype,
++ * followed by arguments which correspond <em>(how? TBD)</em> to
++ * all the parameters of the target.
++ * The target and handler must return the same type.
++ * <p> Here is pseudocode for the resulting adapter:
++ * <blockquote><pre>
++ * T target(A...);
++ * T handler(ExType, A...);
++ * T adapter(A... a) {
++ * try {
++ * return target(a...);
++ * } catch (ExType ex) {
++ * return handler(ex, a...);
++ * }
++ * }
++ * </pre></blockquote>
++ * @param target method handle to call
++ * @param exType the type of exception which the handler will catch
++ * @param handler method handle to call if a matching exception is thrown
++ * @return method handle which incorporates the specified try/catch logic
++ * @throws IllegalArgumentException if {@code handler} does not accept
++ * the given exception type, or if the method handle types do
++ * not match in their return types and their
++ * corresponding parameters
++ */
++ public static
++ MethodHandle catchException(MethodHandle target,
++ Class<? extends Throwable> exType,
++ MethodHandle handler) {
++ MethodType targetType = target.type();
++ MethodType handlerType = handler.type();
++ boolean ok = (targetType.parameterCount() ==
++ handlerType.parameterCount() - 1);
++// for (int i = 0; ok && i < numExArgs; i++) {
++// if (targetType.parameterType(i) != handlerType.parameterType(1+i))
++// ok = false;
++// }
++ if (!ok)
++ throw newIllegalArgumentException("target and handler types do not match");
++ return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
++ }
++
++ /**
++ * Produce a method handle which will throw exceptions of the given {@code exType}.
++ * The method handle will accept a single argument of {@code exType},
++ * and immediately throw it as an exception.
++ * The method type will nominally specify a return of {@code returnType}.
++ * The return type may be anything convenient: It doesn't matter to the
++ * method handle's behavior, since it will never return normally.
++ */
++ public static
++ MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
++ return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.make(returnType, exType));
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Adapt a target method handle {@code target} by pre-processing
++ * some of its arguments, and then calling the target with
++ * the result of the pre-processing, plus all original arguments.
++ * <p>
++ * The pre-processing is performed by a second method handle, the {@code combiner}.
++ * The first {@code foldArgs} arguments passed to the adapter,
++ * are copied to the combiner, which then produces a result.
++ * After this, control passes to the {@code target}, with both the result
++ * of the combiner, and all the original incoming arguments.
++ * <p>
++ * The first argument type of the target must be identical with the
++ * return type of the combiner. The combiner must accept {@code foldArgs}
++ * arguments, and those must be identical in type with the corresponding
++ * arguments of the target (those following the initial argument).
++ * The resulting adapter is the same type as the target, except that the
++ * initial argument type of the target is dropped.
+ * <p>
+ * (Note that {@link #dropArguments} can be used to remove any arguments
+- * that either the {@code combiner} or {@code target} does not wish to receive.)
++ * that either the {@code combiner} or {@code target} does not wish to receive.
++ * If some of the incoming arguments are destined only for the combiner,
++ * consider using {@link #collectArguments} instead, since those
++ * arguments will not need to be live on the stack on entry to the
++ * target.)
+ * <p>
+- * The combiner handle must have the same argument types as the
+- * target handle, but must return {@link MethodHandle} instead of
+- * the ultimate return type. The returned method handle, in turn,
+- * is required to have exactly the given final method type.
++ * The first argument of the target must be identical with the
++ * return value of the combiner.
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>
+- * signature V(A[pos]..., B...);
+- * signature T(A[pos]..., V, B...);
+- * T target(A... a, V v, B... b);
+- * V combiner(A..., B...);
++ * // there are foldArgs arguments in the A sequence
++ * T target(V, A[foldArgs]..., B...);
++ * V combiner(A...);
+ * T adapter(A... a, B... b) {
+- * V v = combiner(a..., b...);
+- * return target(a..., v, b...);
++ * V v = combiner(a...);
++ * return target(v, a..., b...);
+ * }
+ * </pre></blockquote>
+ * @param target the method handle to invoke after arguments are combined
+ * @param pos where the return value of {@code combiner} is to
+ * be inserted as an argument to {@code target}
+ * @param combiner method handle to call initially on the incoming arguments
+- * @return method handle which incorporates the specified dispatch logic
+- * @throws IllegalArgumentException if {@code combiner} does not itself
+- * return either void or the {@code pos}-th argument of {@code target},
+- * or does not have the same argument types as {@code target}
+- * (minus the inserted argument)
++ * @return method handle which incorporates the specified argument folding logic
++ * @throws IllegalArgumentException if the first argument type of
++ * {@code target} is not the same as {@code combiner}'s return type,
++ * or if the next {@code foldArgs} argument types of {@code target}
++ * are not identical with the argument types of {@code combiner}
+ */
+ public static
+- MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
+- MethodType mhType = target.type();
+- Class<?> combineType = combiner.type().returnType();
+- MethodType incomingArgs;
+- if (pos < 0) {
+- // No inserted argument; target & combiner must have same argument types.
+- incomingArgs = mhType;
+- if (!incomingArgs.changeReturnType(combineType).equals(combiner.type()))
+- throw newIllegalArgumentException("target and combiner types do not match");
+- } else {
+- // Inserted argument.
+- if (pos >= mhType.parameterCount()
+- || mhType.parameterType(pos) != combineType)
+- throw newIllegalArgumentException("inserted combiner argument does not match target");
+- incomingArgs = mhType.dropParameterType(pos);
+- }
+- if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
++ MethodHandle foldArguments(MethodHandle target, MethodHandle combiner, int foldArgs) {
++ MethodType targetType = target.type();
++ MethodType combinerType = combiner.type();
++ boolean ok = (targetType.parameterCount() >= 1 + foldArgs &&
++ combinerType.parameterCount() == foldArgs);
++ if (!ok)
+ throw newIllegalArgumentException("target and combiner types do not match");
+- }
+- return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
++ return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, combiner);
+ }
+-
+ }
diff --git a/src/share/classes/java/dyn/MethodType.java b/src/share/classes/java/dyn/MethodType.java
--- a/src/share/classes/java/dyn/MethodType.java
+++ b/src/share/classes/java/dyn/MethodType.java
@@ -1180,6 +1472,38 @@ diff --git a/src/share/classes/sun/dyn/F
}
/** Make a copy of self, with new fields. */
+diff --git a/src/share/classes/sun/dyn/FilterOneArgument.java b/src/share/classes/sun/dyn/FilterOneArgument.java
+--- a/src/share/classes/sun/dyn/FilterOneArgument.java
++++ b/src/share/classes/sun/dyn/FilterOneArgument.java
+@@ -27,7 +27,6 @@
+
+ import java.dyn.JavaMethodHandle;
+ import java.dyn.MethodHandle;
+-import java.dyn.MethodHandles;
+ import java.dyn.MethodType;
+
+ /**
+@@ -42,16 +41,16 @@
+ protected final MethodHandle filter; // Object -> Object
+ protected final MethodHandle target; // Object -> Object
+
+- protected Object entryPoint(Object argument) {
++ protected Object invoke(Object argument) {
+ Object filteredArgument = filter.<Object>invoke(argument);
+ return target.<Object>invoke(filteredArgument);
+ }
+
+- private static final MethodHandle entryPoint =
+- MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1));
++ private static final MethodHandle INVOKE =
++ MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.makeGeneric(1));
+
+ protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
+- super(entryPoint);
++ super(INVOKE);
+ this.filter = filter;
+ this.target = target;
+ }
diff --git a/src/share/classes/sun/dyn/FromGeneric.java b/src/share/classes/sun/dyn/FromGeneric.java
--- a/src/share/classes/sun/dyn/FromGeneric.java
+++ b/src/share/classes/sun/dyn/FromGeneric.java
@@ -1322,7 +1646,7 @@ diff --git a/src/share/classes/sun/dyn/M
diff --git a/src/share/classes/sun/dyn/MethodHandleImpl.java b/src/share/classes/sun/dyn/MethodHandleImpl.java
--- a/src/share/classes/sun/dyn/MethodHandleImpl.java
+++ b/src/share/classes/sun/dyn/MethodHandleImpl.java
-@@ -25,12 +25,15 @@
+@@ -25,12 +25,16 @@
package sun.dyn;
@@ -1334,11 +1658,35 @@ diff --git a/src/share/classes/sun/dyn/M
import sun.dyn.util.VerifyType;
import java.dyn.NoAccessException;
+import java.util.ArrayList;
++import sun.dyn.empty.Empty;
+import sun.dyn.util.ValueConversions;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
-@@ -274,72 +277,145 @@
+@@ -203,8 +207,11 @@
+ if (info instanceof DirectMethodHandle) {
+ DirectMethodHandle dmh = (DirectMethodHandle) info;
+ if (receiver == null ||
+- dmh.type().parameterType(0).isAssignableFrom(receiver.getClass()))
+- target = dmh;
++ dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
++ MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
++ MethodType newType = target.type().dropParameterType(0);
++ return convertArguments(token, bmh, newType, bmh.type(), null);
++ }
+ }
+ }
+ if (target instanceof DirectMethodHandle)
+@@ -223,7 +230,7 @@
+ MethodHandle bindArgument(Access token,
+ MethodHandle target, int argnum, Object receiver) {
+ Access.check(token);
+- throw new UnsupportedOperationException("NYI");
++ return new BoundMethodHandle(target, receiver, argnum);
+ }
+
+ public static MethodHandle convertArguments(Access token,
+@@ -274,76 +281,286 @@
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
MethodType midType = MethodType.make(newType.returnType(), ptypes);
// after spreading, some arguments may need further conversion
@@ -1487,8 +1835,6 @@ diff --git a/src/share/classes/sun/dyn/M
+ int nargs = type.parameterCount();
+ if (nargs < GuardWithTest.INVOKES.length) {
+ MethodType gtype = type.generic();
-+ if (type == gtype)
-+ return new GuardWithTest(test, target, fallback);
+ MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
+ MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
+ MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
@@ -1509,7 +1855,18 @@ diff --git a/src/share/classes/sun/dyn/M
- MethodHandles.convertArguments(target, boxtype),
- MethodHandles.convertArguments(fallback, boxtype));
- return MethodHandles.convertArguments(boxguard, type);
-- }
++ }
++
++ private static class GuardWithCatch extends JavaMethodHandle {
++ private final MethodHandle target;
++ private final Class<? extends Throwable> exType;
++ private final MethodHandle catcher;
++ public GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
++ super(INVOKES[target.type().parameterCount()]);
++ this.target = target;
++ this.exType = exType;
++ this.catcher = catcher;
+ }
- // Got here? Reduced calling sequence to Object(Object).
- class Guarder {
- Object invoke(Object x) {
@@ -1524,12 +1881,142 @@ diff --git a/src/share/classes/sun/dyn/M
- MethodType invokeType = MethodType.makeGeneric(0, true);
- MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType);
- return MethodHandles.collectArguments(vh, target.type());
-- }
-- }
++ private Object invoke_L0() throws Throwable {
++ try {
++ return target.<Object>invoke();
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t);
+ }
+ }
- return new Guarder().handle();
++ private Object invoke_L1(Object a0) throws Throwable {
++ try {
++ return target.<Object>invoke(a0);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0);
++ }
++ }
++ private Object invoke_L2(Object a0, Object a1) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1);
++ }
++ }
++ private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2);
++ }
++ }
++ private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2, a3);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2, a3);
++ }
++ }
++ private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2, a3, a4);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2, a3, a4);
++ }
++ }
++ private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2, a3, a4, a5);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5);
++ }
++ }
++ private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6);
++ }
++ }
++ private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
++ try {
++ return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
++ } catch (Throwable t) {
++ if (!exType.isInstance(t)) throw t;
++ return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6, a7);
++ }
++ }
++ static MethodHandle[] makeInvokes() {
++ ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
++ MethodHandles.Lookup lookup = IMPL_LOOKUP;
++ for (;;) {
++ int nargs = invokes.size();
++ String name = "invoke_L"+nargs;
++ MethodHandle invoke = null;
++ try {
++ invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.makeGeneric(nargs));
++ } catch (NoAccessException ex) {
++ }
++ if (invoke == null) break;
++ invokes.add(invoke);
++ }
++ assert(invokes.size() == 9); // current number of methods
++ return invokes.toArray(new MethodHandle[0]);
++ };
++ static final MethodHandle[] INVOKES = makeInvokes();
++ }
++
++
++ public static
++ MethodHandle makeGuardWithCatch(Access token,
++ MethodHandle target,
++ Class<? extends Throwable> exType,
++ MethodHandle catcher) {
++ Access.check(token);
++ MethodType type = target.type();
++ int nargs = type.parameterCount();
++ if (nargs < GuardWithCatch.INVOKES.length) {
++ MethodType gtype = type.generic();
++ MethodType catchType = gtype.insertParameterType(0, Throwable.class);
++ MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
++ MethodHandle gcatcher = convertArguments(token, catcher, catchType, type, null);
++ MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
++ return convertArguments(token, gguard, type, gtype, null);
++ } else {
++ MethodType gtype = MethodType.makeGeneric(1);
++ MethodType catchType = gtype.insertParameterType(0, Throwable.class);
++ MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
++ MethodHandle gcatcher = spreadArguments(token, catcher, catchType, 1);
++ MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
++ return collectArguments(token, gguard, type, 0, null);
++ }
}
public static
+- MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
++ MethodHandle throwException(Access token, MethodType type) {
++ Access.check(token);
++ return AdapterMethodHandle.makeRetypeOnly(token, type, THROW_EXCEPTION, true);
++ }
++
++ static final MethodHandle THROW_EXCEPTION
++ = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
++ MethodType.make(Empty.class, Throwable.class));
++ static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
++
++ public static
++ MethodHandle foldArguments(Access token, MethodHandle target, MethodHandle combiner) {
+ Access.check(token);
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
diff --git a/src/share/classes/sun/dyn/MethodHandleNatives.java b/src/share/classes/sun/dyn/MethodHandleNatives.java
--- a/src/share/classes/sun/dyn/MethodHandleNatives.java
+++ b/src/share/classes/sun/dyn/MethodHandleNatives.java
@@ -2276,6 +2763,20 @@ diff --git a/src/share/classes/sun/dyn/T
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
+diff --git a/src/share/classes/sun/dyn/empty/Empty.java b/src/share/classes/sun/dyn/empty/Empty.java
+--- a/src/share/classes/sun/dyn/empty/Empty.java
++++ b/src/share/classes/sun/dyn/empty/Empty.java
+@@ -29,6 +29,10 @@
+ * An empty class in an empty package.
+ * Used as a proxy for unprivileged code, since making access checks
+ * against it will only succeed against public methods in public types.
++ * <p>
++ * This class also stands (internally to sun.dyn) for the type of a
++ * value that cannot be produced, because the expression of this type
++ * always returns abnormally. (Cf. Nothing in the closures proposal.)
+ * @author jrose
+ */
+ public class Empty {
diff --git a/src/share/classes/sun/dyn/util/BytecodeSignature.java b/src/share/classes/sun/dyn/util/BytecodeDescriptor.java
rename from src/share/classes/sun/dyn/util/BytecodeSignature.java
rename to src/share/classes/sun/dyn/util/BytecodeDescriptor.java
@@ -2296,15 +2797,18 @@ diff --git a/src/share/classes/sun/dyn/u
diff --git a/src/share/classes/sun/dyn/util/ValueConversions.java b/src/share/classes/sun/dyn/util/ValueConversions.java
--- a/src/share/classes/sun/dyn/util/ValueConversions.java
+++ b/src/share/classes/sun/dyn/util/ValueConversions.java
-@@ -27,6 +27,7 @@
+@@ -27,7 +27,10 @@
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
+import java.util.ArrayList;
++import java.util.Arrays;
import java.util.EnumMap;
++import java.util.List;
import sun.dyn.Access;
import sun.dyn.AdapterMethodHandle;
-@@ -37,6 +38,7 @@
+ import sun.dyn.MethodHandleImpl;
+@@ -37,6 +40,7 @@
private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN);
private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
@@ -2312,14 +2816,14 @@ diff --git a/src/share/classes/sun/dyn/u
EnumMap<Wrapper, MethodHandle>[] caches
= (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here
for (int i = 0; i < n; i++)
-@@ -560,4 +562,65 @@
+@@ -560,4 +564,127 @@
private static MethodHandle retype(MethodType type, MethodHandle mh) {
return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
}
+
-+ private static final Object[] NO_ARGS = {};
++ private static final Object[] NO_ARGS_ARRAY = {};
+ private static Object[] makeArray(Object... args) { return args; }
-+ private static Object[] array() { return NO_ARGS; }
++ private static Object[] array() { return NO_ARGS_ARRAY; }
+ private static Object[] array(Object a0)
+ { return makeArray(a0); }
+ private static Object[] array(Object a0, Object a1)
@@ -2365,14 +2869,76 @@ diff --git a/src/share/classes/sun/dyn/u
+ }
+ assert(arrays.size() == 11); // current number of methods
+ return arrays.toArray(new MethodHandle[0]);
-+ };
++ }
+ static final MethodHandle[] ARRAYS = makeArrays();
++
+ /** Return a method handle that takes the indicated number of Object
+ * arguments and returns an Object array of them, as if for varargs.
+ */
+ public static MethodHandle varargsArray(int nargs) {
+ if (nargs < ARRAYS.length)
+ return ARRAYS[nargs];
++ // else need to spin bytecode or do something else fancy
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
++ private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
++ private static List<Object> list() { return NO_ARGS_LIST; }
++ private static List<Object> list(Object a0)
++ { return makeList(a0); }
++ private static List<Object> list(Object a0, Object a1)
++ { return makeList(a0, a1); }
++ private static List<Object> list(Object a0, Object a1, Object a2)
++ { return makeList(a0, a1, a2); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
++ { return makeList(a0, a1, a2, a3); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4)
++ { return makeList(a0, a1, a2, a3, a4); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4, Object a5)
++ { return makeList(a0, a1, a2, a3, a4, a5); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4, Object a5, Object a6)
++ { return makeList(a0, a1, a2, a3, a4, a5, a6); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4, Object a5, Object a6, Object a7)
++ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4, Object a5, Object a6, Object a7,
++ Object a8)
++ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
++ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
++ Object a4, Object a5, Object a6, Object a7,
++ Object a8, Object a9)
++ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
++ static MethodHandle[] makeLists() {
++ ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
++ MethodHandles.Lookup lookup = IMPL_LOOKUP;
++ for (;;) {
++ int nargs = arrays.size();
++ MethodType type = MethodType.makeGeneric(nargs).changeReturnType(List.class);
++ String name = "list";
++ MethodHandle array = null;
++ try {
++ array = lookup.findStatic(ValueConversions.class, name, type);
++ } catch (NoAccessException ex) {
++ }
++ if (array == null) break;
++ arrays.add(array);
++ }
++ assert(arrays.size() == 11); // current number of methods
++ return arrays.toArray(new MethodHandle[0]);
++ }
++ static final MethodHandle[] LISTS = makeLists();
++
++ /** Return a method handle that takes the indicated number of Object
++ * arguments and returns List.
++ */
++ public static MethodHandle varargsList(int nargs) {
++ if (nargs < LISTS.length)
++ return LISTS[nargs];
+ // else need to spin bytecode or do something else fancy
+ throw new UnsupportedOperationException("NYI");
+ }
@@ -2434,6 +3000,72 @@ diff --git a/src/share/classes/sun/dyn/u
+ self.isProtected() ? "member is protected" : "member is private to package");
+ }
}
+diff --git a/src/share/classes/sun/dyn/util/VerifyType.java b/src/share/classes/sun/dyn/util/VerifyType.java
+--- a/src/share/classes/sun/dyn/util/VerifyType.java
++++ b/src/share/classes/sun/dyn/util/VerifyType.java
+@@ -26,6 +26,7 @@
+ package sun.dyn.util;
+
+ import java.dyn.MethodType;
++import sun.dyn.empty.Empty;
+
+ /**
+ * This class centralizes information about the JVM verifier
+@@ -73,29 +74,28 @@
+ }
+
+ /**
+- * Is the given type either java.lang.Void or java.lang.Null?
+- * These types serve as markers for bare nulls and therefore
+- * may be promoted to any type. This is secure, since
++ * Is the given type java.lang.Null or an equivalent null-only type?
+ */
+ public static boolean isNullType(Class<?> type) {
+ if (type == null) return false;
+- return type == NULL_CLASS_1 || type == NULL_CLASS_2;
++ return type == NULL_CLASS
++ // This one may also be used as a null type.
++ // TO DO: Decide if we really want to legitimize it here.
++ // Probably we do, unless java.lang.Null really makes it into Java 7
++ //|| type == Void.class
++ // Locally known null-only class:
++ || type == Empty.class
++ ;
+ }
+- private static final Class<?> NULL_CLASS_1, NULL_CLASS_2;
++ private static final Class<?> NULL_CLASS;
+ static {
+- Class<?> nullClass1 = null, nullClass2 = null;
++ Class<?> nullClass = null;
+ try {
+- nullClass1 = Class.forName("java.lang.Null");
++ nullClass = Class.forName("java.lang.Null");
+ } catch (ClassNotFoundException ex) {
+ // OK, we'll cope
+ }
+- NULL_CLASS_1 = nullClass1;
+-
+- // This one may also be used as a null type.
+- // TO DO: Decide if we really want to legitimize it here.
+- // Probably we do, unless java.lang.Null really makes it into Java 7
+- nullClass2 = Void.class;
+- NULL_CLASS_2 = nullClass2;
++ NULL_CLASS = nullClass;
+ }
+
+ /**
+@@ -191,6 +191,11 @@
+ // to be captured as a garbage int.
+ // Caller promises that the actual value will be disregarded.
+ return dst == int.class ? 1 : 0;
++ if (isNullType(src))
++ // Special permission for raw conversions: allow a null
++ // to be reinterpreted as anything. For objects, it is safe,
++ // and for primitives you get a garbage value (probably zero).
++ return 1;
+ if (!src.isPrimitive())
+ return 0;
+ Wrapper sw = Wrapper.forPrimitiveType(src);
diff --git a/src/share/classes/sun/dyn/util/Wrapper.java b/src/share/classes/sun/dyn/util/Wrapper.java
--- a/src/share/classes/sun/dyn/util/Wrapper.java
+++ b/src/share/classes/sun/dyn/util/Wrapper.java