# HG changeset patch # User jrose # Date 1297416384 28800 # Node ID 9e2483e6cfabbdd0fd0797d293fd9bf985d5ced8 # Parent c5df55701e9163ecf9a2b2335dc616368d271863 7013417: JSR 292 needs to support variadic method handle calls Summary: Implement MH.asVarargsCollector, etc., and remove withTypeHandler. Reviewed-by: twisti diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/java/dyn/MethodHandle.java --- a/jdk/src/share/classes/java/dyn/MethodHandle.java Thu Feb 10 16:24:40 2011 -0800 +++ b/jdk/src/share/classes/java/dyn/MethodHandle.java Fri Feb 11 01:26:24 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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 @@ -134,6 +134,11 @@ * constant pool entry. * For more details, see the package summary.) *
+ * Method handles produced by lookups or constant loads from methods or + * constructors with the variable arity modifier bit ({@code 0x0080}) + * have a corresponding variable arity, as if they were defined with + * the help of {@link #asVarargsCollector asVarargsCollector}. + *
* Java code can also use a reflective API called * {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup} * for creating and calling method handles. @@ -175,6 +180,9 @@ // mt is {Object[] => List} mt = MethodType.methodType(java.util.List.class, Object[].class); mh = lookup.findStatic(java.util.Arrays.class, "asList", mt); +assert(mh.isVarargsCollector()); +x = mh.invokeGeneric("one", "two"); +assert(x.equals(java.util.Arrays.asList("one","two"))); // mt is {(Object,Object,Object) => Object} mt = MethodType.genericMethodType(3); mh = MethodHandles.collectArguments(mh, mt); @@ -307,26 +315,6 @@ } /** - * Returns a string representation of the method handle, - * starting with the string {@code "MethodHandle"} and - * ending with the string representation of the method handle's type. - * In other words, this method returns a string equal to the value of: - *
- *- * "MethodHandle" + type().toString() - *
- * Note: Future releases of this API may add further information - * to the string representation. - * Therefore, the present syntax should not be parsed by applications. - * - * @return a string representation of the method handle - */ - @Override - public String toString() { - return MethodHandleImpl.getNameString(IMPL_TOKEN, this); - } - - /** * Invoke the method handle, allowing any caller signature, but requiring an exact signature match. * The signature at the call site of {@code invokeExact} must * exactly match this method handle's {@link #type type}. @@ -338,7 +326,7 @@ /** * Invoke the method handle, allowing any caller signature, - * and optionally performing conversions for arguments and return types. + * and optionally performing conversions on arguments and return values. *
* If the call site signature exactly matches this method handle's {@link #type type}, * the call proceeds as if by {@link #invokeExact invokeExact}. @@ -353,14 +341,13 @@ * adaptations directly on the caller's arguments, * and call the target method handle according to its own exact type. *
- * If the method handle is equipped with a - * {@linkplain #withTypeHandler type handler}, the handler must produce - * an entry point of the call site's exact type. - * Otherwise, the signature at the call site of {@code invokeGeneric} must - * be a valid argument to the standard {@code asType} method. + * The signature at the call site of {@code invokeGeneric} must + * be a valid argument to the receivers {@code asType} method. * In particular, the caller must specify the same argument arity - * as the callee's type. + * as the callee's type, + * if the callee is not a {@linkplain #asVarargsCollector variable arity collector}. * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type signature + * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable; @@ -400,14 +387,14 @@ *
* This call is equivalent to the following code: *
* @param arguments the arguments to pass to the target * @return the result returned by the target * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the arguments * @throws Throwable anything thrown by the target method invocation - * @see MethodHandles#varargsInvoker + * @see MethodHandles#spreadInvoker */ public final Object invokeWithArguments(Object... arguments) throws Throwable { int argc = arguments == null ? 0 : arguments.length; @@ -456,7 +443,7 @@ } // more than ten arguments get boxed in a varargs list: - MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0); + MethodHandle invoker = invokers(type).spreadInvoker(0); return invoker.invokeExact(this, arguments); } /** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */ @@ -488,13 +475,7 @@ * to match up the caller's and callee's types. *- * MethodHandle invoker = MethodHandles.varargsInvoker(this.type(), 0); + * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0); * Object result = invoker.invokeExact(this, arguments); *
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments}, - * except for method handles produced by {@link #withTypeHandler withTypeHandler}, - * in which case the specified type handler is used for calls to {@code asType}. - *
- * Note that the default behavior of {@code asType} only performs - * pairwise argument conversion and return value conversion. - * Because of this, unless the method handle has a type handler, - * the original type and new type must have the same number of arguments. + * except for variable arity method handles produced by {@link #asVarargsCollector asVarargsCollector}. * * @param newType the expected type of the new method handle * @return a method handle which delegates to {@code this} after performing @@ -508,14 +489,16 @@ } /** - * Produce a method handle which adapts, as its target, + * Make an adapter which accepts a trailing array argument + * and spreads its elements as positional arguments. + * The new method handle adapts, as its target, * the current method handle. The type of the adapter will be * the same as the type of the target, except that the final * {@code arrayLength} parameters of the target's type are replaced * by a single array parameter of type {@code arrayType}. *
* If the array element type differs from any of the corresponding - * argument types on original target, + * argument types on the original target, * the original target is adapted to take the array elements directly, * as if by a call to {@link #asType asType}. *
@@ -539,6 +522,7 @@ * @throws IllegalArgumentException if target does not have at least * {@code arrayLength} parameter types * @throws WrongMethodTypeException if the implied {@code asType} call fails + * @see #asCollector */ public final MethodHandle asSpreader(Class> arrayType, int arrayLength) { Class> arrayElement = arrayType.getComponentType(); @@ -553,13 +537,15 @@ } /** - * Produce a method handle which adapts, as its target, + * Make an adapter which accepts a given number of trailing + * positional arguments and collects them into an array argument. + * The new method handle adapts, as its target, * the current method handle. The type of the adapter will be * the same as the type of the target, except that a single trailing * parameter (usually of type {@code arrayType}) is replaced by * {@code arrayLength} parameters whose type is element type of {@code arrayType}. *
- * If the array type differs from the final argument type on original target, + * If the array type differs from the final argument type on the original target, * the original target is adapted to take the array type directly, * as if by a call to {@link #asType asType}. *
@@ -570,21 +556,31 @@ * What the target eventually returns is returned unchanged by the adapter. *
* (The array may also be a shared constant when {@code arrayLength} is zero.) - * @param arrayType usually {@code Object[]}, the type of the array argument which will collect the arguments + *
+ * (Note: The {@code arrayType} is often identical to the last + * parameter type of the original target. + * It is an explicit argument for symmetry with {@code asSpreader}, and also + * to allow the target to use a simple {@code Object} as its last parameter type.) + *
+ * In order to create a collecting adapter which is not restricted to a particular
+ * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
* @param arrayLength the number of arguments to collect into a new array argument
* @return a new method handle which collects some trailing argument
* into an array, before calling the original method handle
* @throws IllegalArgumentException if {@code arrayType} is not an array type
- or {@code arrayType} is not assignable to this method handle's trailing parameter type
- * @throws IllegalArgumentException if {@code arrayLength} is not
- * a legal array size
+ * or {@code arrayType} is not assignable to this method handle's trailing parameter type,
+ * or {@code arrayLength} is not a legal array size
* @throws WrongMethodTypeException if the implied {@code asType} call fails
+ * @see #asSpreader
+ * @see #asVarargsCollector
*/
public final MethodHandle asCollector(Class> arrayType, int arrayLength) {
Class> arrayElement = arrayType.getComponentType();
if (arrayElement == null) throw newIllegalArgumentException("not an array type");
MethodType oldType = type();
int nargs = oldType.parameterCount();
+ if (nargs == 0) throw newIllegalArgumentException("no trailing argument");
MethodType newType = oldType.dropParameterTypes(nargs-1, nargs);
newType = newType.insertParameterTypes(nargs-1,
java.util.Collections.
+ * The type and behavior of the adapter will be the same as
+ * the type and behavior of the target, except that certain
+ * {@code invokeGeneric} and {@code asType} requests can lead to
+ * trailing positional arguments being collected into target's
+ * trailing parameter.
+ * Also, the last parameter type of the adapter will be
+ * {@code arrayType}, even if the target has a different
+ * last parameter type.
+ *
+ * When called with {@link #invokeExact invokeExact}, the adapter invokes
+ * the target with no argument changes.
+ * (Note: This behavior is different from a
+ * {@linkplain #asCollector fixed arity collector},
+ * since it accepts a whole array of indeterminate length,
+ * rather than a fixed number of arguments.)
+ *
+ * When called with {@link #invokeGeneric invokeGeneric}, if the caller
+ * type is the same as the adapter, the adapter invokes the target as with
+ * {@code invokeExact}.
+ * (This is the normal behavior for {@code invokeGeneric} when types match.)
+ *
+ * Otherwise, if the caller and adapter arity are the same, and the
+ * trailing parameter type of the caller is a reference type identical to
+ * or assignable to the trailing parameter type of the adapter,
+ * the arguments and return values are converted pairwise,
+ * as if by {@link MethodHandles#convertArguments convertArguments}.
+ * (This is also normal behavior for {@code invokeGeneric} in such a case.)
+ *
+ * Otherwise, the arities differ, or the adapter's trailing parameter
+ * type is not assignable from the corresponding caller type.
+ * In this case, the adapter replaces all trailing arguments from
+ * the original trailing argument position onward, by
+ * a new array of type {@code arrayType}, whose elements
+ * comprise (in order) the replaced arguments.
+ *
+ * The caller type must provides as least enough arguments,
+ * and of the correct type, to satisfy the target's requirement for
+ * positional arguments before the trailing array argument.
+ * Thus, the caller must supply, at a minimum, {@code N-1} arguments,
+ * where {@code N} is the arity of the target.
+ * Also, there must exist conversions from the incoming arguments
+ * to the target's arguments.
+ * As with other uses of {@code invokeGeneric}, if these basic
+ * requirements are not fulfilled, a {@code WrongMethodTypeException}
+ * may be thrown.
+ *
+ * In all cases, what the target eventually returns is returned unchanged by the adapter.
+ *
+ * In the final case, it is exactly as if the target method handle were
+ * temporarily adapted with a {@linkplain #asCollector fixed arity collector}
+ * to the arity required by the caller type.
+ * (As with {@code asCollector}, if the array length is zero,
+ * a shared constant may be used instead of a new array.
+ * If the implied call to {@code asCollector} would throw
+ * an {@code IllegalArgumentException} or {@code WrongMethodTypeException},
+ * the call to the variable arity adapter must throw
+ * {@code WrongMethodTypeException}.)
+ *
+ * The behavior of {@link #asType asType} is also specialized for
+ * variable arity adapters, to maintain the invariant that
+ * {@code invokeGeneric} is always equivalent to an {@code asType}
+ * call to adjust the target type, followed by {@code invokeExact}.
+ * Therefore, a variable arity adapter responds
+ * to an {@code asType} request by building a fixed arity collector,
+ * if and only if the adapter and requested type differ either
+ * in arity or trailing argument type.
+ * The resulting fixed arity collector has its type further adjusted
+ * (if necessary) to the requested type by pairwise conversion,
+ * as if by another application of {@code asType}.
+ *
+ * When a method handle is obtained by executing an {@code ldc} instruction
+ * of a {@code CONSTANT_MethodHandle} constant, and the target method is marked
+ * as a variable arity method (with the modifier bit {@code 0x0080}),
+ * the method handle will accept multiple arities, as if the method handle
+ * constant were created by means of a call to {@code asVarargsCollector}.
+ *
+ * In order to create a collecting adapter which collects a predetermined
+ * number of arguments, and whose type reflects this predetermined number,
+ * use {@link #asCollector asCollector} instead.
+ *
+ * No method handle transformations produce new method handles with
+ * variable arity, unless they are documented as doing so.
+ * Therefore, besides {@code asVarargsCollector},
+ * all methods in {@code MethodHandle} and {@code MethodHandles}
+ * will return a method handle with fixed arity,
+ * except in the cases where they are specified to return their original
+ * operand (e.g., {@code asType} of the method handle's own type).
+ *
+ * Calling {@code asVarargsCollector} on a method handle which is already
+ * of variable arity will produce a method handle with the same type and behavior.
+ * It may (or may not) return the original variable arity method handle.
+ *
+ * Here is an example, of a list-making variable arity method handle:
+ *
+ * These rules are designed as a dynamically-typed variation
+ * of the Java rules for variable arity methods.
+ * In both cases, callers to a variable arity method or method handle
+ * can either pass zero or more positional arguments, or else pass
+ * pre-collected arrays of any length. Users should be aware of the
+ * special role of the final argument, and of the effect of a
+ * type match on that final argument, which determines whether
+ * or not a single trailing argument is interpreted as a whole
+ * array or a single element of an array to be collected.
+ * Note that the dynamic type of the trailing argument has no
+ * effect on this decision, only a comparison between the static
+ * type signature of the call site and the type of the method handle.)
+ *
+ * As a result of the previously stated rules, the variable arity behavior
+ * of a method handle may be suppressed, by binding it to the exact invoker
+ * of its own type, as follows:
+ *
- * The new method handle will have the same behavior as the
- * old one when invoked by {@code invokeExact}.
- * For {@code invokeGeneric} calls which exactly match
- * the method type, the two method handles will also
- * have the same behavior.
- * For other {@code invokeGeneric} calls, the {@code typeHandler}
- * will control the behavior of the new method handle.
- *
- * Thus, a method handle with an {@code asType} handler can
- * be configured to accept more than one arity of {@code invokeGeneric}
- * call, and potentially every possible arity.
- * It can also be configured to supply default values for
- * optional arguments, when the caller does not specify them.
- *
- * The given method handle must take two arguments and return
- * one result. The result it returns must be a method handle
- * of exactly the requested type. If the result returned by
- * the target is null, a {@link NullPointerException} is thrown,
- * else if the type of the target does not exactly match
- * the requested type, a {@link WrongMethodTypeException} is thrown.
- *
- * A method handle's type handler is not guaranteed to be called every
- * time its {@code asType} or {@code invokeGeneric} method is called.
- * If the implementation is faced is able to prove that an equivalent
- * type handler call has already occurred (on the same two arguments),
- * it may substitute the result of that previous invocation, without
- * making a new invocation. Thus, type handlers should not (in general)
- * perform significant side effects.
- *
- * Therefore, the type handler is invoked as if by this code:
+ * Returns a string representation of the method handle,
+ * starting with the string {@code "MethodHandle"} and
+ * ending with the string representation of the method handle's type.
+ * In other words, this method returns a string equal to the value of:
*
- * For example, here is a list-making variable-arity method handle:
- *
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
- * under which the lookup class could have compiled a call to {@code M}.
+ * under which the lookup class could have compiled a call to {@code M},
+ * or could have compiled an {@code ldc} instruction loading a
+ * {@code CONSTANT_MethodHandle} of M.
+ * The same point is true of fields and constructors.
*
* In some cases, this access is obtained by the Java compiler by creating
* an wrapper method to access a private method of another class
@@ -379,6 +382,10 @@
* 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.
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
* @param refc the class from which the method is accessed
* @param name the name of the method
* @param type the type of the method
@@ -403,6 +410,10 @@
* implementation to enter.
* (The dispatching action is identical with that performed by an
* {@code invokevirtual} or {@code invokeinterface} instruction.)
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
* @param refc 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
@@ -427,6 +438,10 @@
*
* Note: The requested type must have a return type of {@code void}.
* This is consistent with the JVM's treatment of constructor signatures.
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
@@ -438,7 +453,23 @@
assert(ctor.isConstructor());
checkAccess(refc, ctor);
MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
- return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH);
+ MethodHandle allocMH = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH);
+ return fixVarargs(allocMH, rawMH);
+ }
+
+ /** Return a version of MH which matches matchMH w.r.t. isVarargsCollector. */
+ private static MethodHandle fixVarargs(MethodHandle mh, MethodHandle matchMH) {
+ boolean va1 = mh.isVarargsCollector();
+ boolean va2 = matchMH.isVarargsCollector();
+ if (va1 == va2) {
+ return mh;
+ } else if (va2) {
+ MethodType type = mh.type();
+ int arity = type.parameterCount();
+ return mh.asVarargsCollector(type.parameterType(arity-1));
+ } else {
+ throw new InternalError("already varargs, but template is not: "+mh);
+ }
}
/**
@@ -458,6 +489,10 @@
* If the explicitly specified caller class is not identical with the
* lookup class, or if this lookup object does not have private access
* privileges, the access fails.
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
* @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "<init>")
* @param type the type of the method, with the receiver argument omitted
@@ -547,13 +582,26 @@
* so that every call to the method handle will invoke the
* requested method on the given receiver.
*
- * This is equivalent to the following expression:
- *
+ * This is equivalent to the following code:
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
* @param m the reflected method
* @return a method handle which can invoke the reflected method
* @exception NoAccessException if access checking fails
@@ -603,6 +657,10 @@
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class,
* as if {@code invokespecial} instruction were being linked.
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
* @param m the reflected method
* @param specialCaller the class nominally calling the method
* @return a method handle which can invoke the reflected method
@@ -628,6 +686,10 @@
*
* If the constructor's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
+ *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
* @param c the reflected constructor
* @return a method handle which can invoke the reflected constructor
* @exception NoAccessException if access checking fails
@@ -637,7 +699,8 @@
assert(ctor.isConstructor());
if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor);
MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
- return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
+ MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
+ return fixVarargs(allocator, rawCtor);
}
/**
@@ -785,7 +848,8 @@
MethodType rawType = mh.type();
if (rawType.parameterType(0) == caller) return mh;
MethodType narrowType = rawType.changeParameterType(0, caller);
- return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null);
+ MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null);
+ return fixVarargs(narrowMH, mh);
}
MethodHandle makeAccessor(Class> refc, String name, Class> type,
@@ -909,22 +973,21 @@
*
* This method is equivalent to the following code (though it may be more efficient):
*
* The method handle may throw an undeclared exception,
* which means any checked exception (or other checked throwable)
@@ -1874,15 +1940,17 @@
* {@link java.dyn.MethodHandles.AsInstanceObject AsInstanceObject}
* in the adapters, so that generic code can extract the underlying
* method handle without knowing where the SAM adapter came from.
+ *
+ * Future versions of this API may accept additional types,
+ * such as abstract classes with single abstract methods.
* @param target the method handle to invoke from the wrapper
* @param samType the desired type of the wrapper, a SAM type
* @return a correctly-typed wrapper for the given {@code target}
- * @throws IllegalArgumentException if the {@code target} throws
- * an undeclared exception
+ * @throws IllegalArgumentException if the {@code samType} is not a
+ * valid argument to this method
+ * @throws WrongMethodTypeException if the {@code target} cannot
+ * be converted to the type required by the SAM type
*/
- // ISSUE: Should we delegate equals/hashCode to the targets?
- // Not useful unless there is a stable equals/hashCode behavior
- // for MethodHandle, but there isn't.
public static
* A constant may refer to a method or constructor with the {@code varargs}
- * bit (hexadecimal {@code 80}) set in its modifier bitmask.
- * The method handle constant produced for such a method behaves the same
+ * bit (hexadecimal {@code 0x0080}) set in its modifier bitmask.
+ * The method handle constant produced for such a method behaves as if
+ * it were created by {@link java.dyn.MethodHandle#asVarargsCollector asVarargsCollector}.
+ * In other words, the constant method handle will exhibit variable arity,
+ * when invoked via {@code invokeGeneric}.
+ * On the other hand, its behavior with respect to {@code invokeExact} will be the same
* as if the {@code varargs} bit were not set.
- * The argument-collecting behavior of {@code varargs} can be emulated by
- * adapting the method handle constant with
- * {@link java.dyn.MethodHandle#asCollector asCollector}.
- * There is no provision for doing this automatically.
*
* Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
* resolve class names, they do not force class initialization.
@@ -369,21 +369,40 @@
* the instruction's bootstrap method will be invoked on three arguments,
* conveying the instruction's caller class, name, and method type.
* If the {@code invokedynamic} instruction specifies one or more static arguments,
- * a fourth argument will be passed to the bootstrap argument,
- * either an {@code Object} reference to the sole extra argument (if there is one)
- * or an {@code Object} array of references to all the arguments (if there are two or more),
- * as if the bootstrap method is a variable-arity method.
+ * those values will be passed as additional arguments to the method handle.
+ * (Note that because there is a limit of 255 arguments to any method,
+ * at most 252 extra arguments can be supplied.)
+ * The bootstrap method will be invoked as if by either {@code invokeGeneric}
+ * or {@code invokeWithArguments}. (There is no way to tell the difference.)
+ * If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
+ * then some or all of the arguments specified here may be collected into a trailing array parameter.
+ * (This is not a special rule, but rather a useful consequence of the interaction
+ * between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
+ * and the {@code java.dyn.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
+ *
+ * Given these rules, here are examples of legal bootstrap method declarations,
+ * given various numbers {@code N} of extra arguments.
+ * The first rows (marked {@code *}) will work for any number of extra arguments.
*
- * The argument and return types listed here are used by the {@code invokeGeneric}
- * call to the bootstrap method.
* As noted above, the actual method type of the bootstrap method can vary.
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
@@ -391,14 +410,8 @@
* In that case, the {@code invokeGeneric} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
- * (If a string constant were passed instead, by badly generated code, that cast would then fail.)
- *
- * If the fourth argument is an array, the array element type must be {@code Object},
- * since object arrays (as produced by the JVM at this point) cannot be converted
- * to other array types.
- *
- * If an array is provided, it will appear to be freshly allocated.
- * That is, the same array will not appear to two bootstrap method calls.
+ * (If a string constant were passed instead, by badly generated code, that cast would then fail,
+ * resulting in an {@code InvokeDynamicBootstrapError}.)
*
* Extra bootstrap method arguments are intended to allow language implementors
* to safely and compactly encode metadata.
@@ -406,24 +419,6 @@
* since each call site could be given its own unique bootstrap method.
* Such a practice is likely to produce large class files and constant pools.
*
- *
- * PROVISIONAL API, WORK IN PROGRESS:
- * (Usage Note: There is no mechanism for specifying five or more positional arguments to the bootstrap method.
- * If there are two or more arguments, the Java code of the bootstrap method is required to extract them from
- * a varargs-style object array.
- * This design uses varargs because it anticipates some use cases where bootstrap arguments
- * contribute components of variable-length structures, such as virtual function tables
- * or interpreter token streams.
- * Such parameters would be awkward or impossible to manage if represented
- * as normal positional method arguments,
- * since there would need to be one Java method per length.
- * On balance, leaving out the varargs feature would cause more trouble to users than keeping it.
- * Also, this design allows bootstrap methods to be called in a limited JVM stack depth.
- * At both the user and JVM level, the difference between varargs and non-varargs
- * calling sequences can easily be bridged via the
- * {@link java.dyn.MethodHandle#asSpreader asSpreader}
- * and {@link java.dyn.MethodHandle#asSpreader asCollector} methods.)
- *
*
- * Until the format of {@code CONSTANT_InvokeDynamic} entries is finalized,
- * the {@code --transitionalJSR292} switch is recommended (and turned on by default).
+ * Before OpenJDK build b123, the format of {@code CONSTANT_InvokeDynamic} is in transition,
+ * and the switch {@code --transitionalJSR292=yes} is recommended.
+ * It is turned off by default, but users of earlier builds may need to turn it on.
*
* A version of this transformation built on top of http://asm.ow2.org/ would be welcome.
* @author John Rose
@@ -116,7 +117,7 @@
public boolean overwrite = false;
public boolean quiet = false;
public boolean verbose = false;
- public boolean transitionalJSR292 = true; // default to false later
+ public boolean transitionalJSR292 = false; // final version is distributed
public boolean all = false;
public int verifySpecifierCount = -1;
@@ -158,6 +159,7 @@
av = avl.toArray(new String[0]);
Class> mainClass = Class.forName(mainClassName, true, makeClassLoader());
java.lang.reflect.Method main = mainClass.getMethod("main", String[].class);
+ try { main.setAccessible(true); } catch (SecurityException ex) { }
main.invoke(null, (Object) av);
}
@@ -223,8 +225,8 @@
private boolean booleanOption(String s) {
if (s == null) return true;
switch (s) {
- case "true": case "yes": case "1": return true;
- case "false": case "no": case "0": return false;
+ case "true": case "yes": case "on": case "1": return true;
+ case "false": case "no": case "off": case "0": return false;
}
throw new IllegalArgumentException("unrecognized boolean flag="+s);
}
@@ -284,7 +286,7 @@
}
File classPathFile(File pathDir, String className) {
- String qualname = className+".class";
+ String qualname = className.replace('.','/')+".class";
qualname = qualname.replace('/', File.separatorChar);
return new File(pathDir, qualname);
}
@@ -339,6 +341,7 @@
private File findClassInPath(String name) {
for (String s : classpath) {
File f = classPathFile(new File(s), name);
+ //System.out.println("Checking for "+f);
if (f.exists() && f.canRead()) {
return f;
}
@@ -353,11 +356,11 @@
}
}
private Class> transformAndLoadClass(File f) throws ClassNotFoundException, IOException {
- if (verbose) System.out.println("Loading class from "+f);
+ if (verbose) System.err.println("Loading class from "+f);
ClassFile cf = new ClassFile(f);
Logic logic = new Logic(cf);
boolean changed = logic.transform();
- if (verbose && !changed) System.out.println("(no change)");
+ if (verbose && !changed) System.err.println("(no change)");
logic.reportPatternMethods(!verbose, keepgoing);
byte[] bytes = cf.toByteArray();
return defineClass(null, bytes, 0, bytes.length);
@@ -525,6 +528,7 @@
throw new IllegalArgumentException("BootstrapMethods length is "+specsLen+" but should be "+verifySpecifierCount);
}
}
+ if (!quiet) System.err.flush();
}
// mark constant pool entries according to participation in patterns
@@ -696,6 +700,18 @@
args.clear();
break;
+ case opc_new:
+ {
+ String type = pool.getString(CONSTANT_Class, (short)i.u2At(1));
+ //System.out.println("new "+type);
+ switch (type) {
+ case "java/lang/StringBuilder":
+ jvm.push("StringBuilder");
+ continue decode; // go to next instruction
+ }
+ break decode; // bail out
+ }
+
case opc_getstatic:
{
// int.class compiles to getstatic Integer.TYPE
@@ -732,8 +748,9 @@
case opc_invokestatic:
case opc_invokevirtual:
+ case opc_invokespecial:
{
- boolean hasRecv = (bc == opc_invokevirtual);
+ boolean hasRecv = (bc != opc_invokestatic);
int methi = i.u2At(1);
char mark = poolMarks[methi];
Short[] ref = pool.getMemberRef((short)methi);
@@ -770,6 +787,7 @@
if (mark == 'T' || mark == 'H' || mark == 'I') {
ownMethod = findMember(cf.methods, ref[1], ref[2]);
}
+ //if (intrinsic != null) System.out.println("intrinsic = "+intrinsic);
switch (intrinsic == null ? "" : intrinsic) {
case "fromMethodDescriptorString":
con = makeMethodTypeCon(args.get(0));
@@ -860,6 +878,15 @@
}
}
break decode;
+ case "StringBuilder.append":
+ // allow calls like ("value = "+x)
+ removeEmptyJVMSlots(args);
+ args.subList(1, args.size()).clear();
+ continue;
+ case "StringBuilder.toString":
+ args.clear();
+ args.add(intrinsic);
+ continue;
}
if (!hasRecv && ownMethod != null && patternMark != 0) {
con = constants.get(ownMethod);
@@ -1506,6 +1533,7 @@
out.write(bytes);
} else {
trueSize = flatten(out);
+ //if (!(item instanceof Code)) System.err.println("wrote complex attr name="+(int)(char)name+" size="+trueSize+" data="+Arrays.toString(flatten()));
}
if (trueSize != size && size >= 0)
System.err.println("warning: attribute size changed "+size+" to "+trueSize);
@@ -1525,7 +1553,7 @@
}
public List
+ *
+MethodHandle asList = publicLookup()
+ .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
+ .asVarargsCollector(Object[].class);
+assertEquals("[]", asList.invokeGeneric().toString());
+assertEquals("[1]", asList.invokeGeneric(1).toString());
+assertEquals("[two, too]", asList.invokeGeneric("two", "too").toString());
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asList.invokeGeneric(argv).toString());
+List ls = (List) asList.invokeGeneric((Object)argv);
+assertEquals(1, ls.size());
+assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
+ *
+ * This transformation has no behavioral effect if the method handle is
+ * not of variable arity.
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+ * @return a new method handle which can collect any number of trailing arguments
+ * into an array, before calling the original method handle
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * or {@code arrayType} is not assignable to this method handle's trailing parameter type
+ * @see #asCollector
+ */
+ public MethodHandle asVarargsCollector(Class> arrayType) {
+ Class> arrayElement = arrayType.getComponentType();
+ if (arrayElement == null) throw newIllegalArgumentException("not an array type");
+ return MethodHandles.asVarargsCollector(this, arrayType);
+ }
+
+ /**
+ * Determine if this method handle
+ * supports {@linkplain #asVarargsCollector variable arity} calls.
+ * Such method handles arise from the following sources:
+ *
+MethodHandle vamh = publicLookup()
+ .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
+ .asVarargsCollector(Object[].class);
+MethodHandle invokeExact = publicLookup()
+ .findVirtual(MethodHandle.class, "invokeExact", vamh.type());
+MethodHandle mh = invokeExact.bindTo(vamh);
+assert(vamh.type().equals(mh.type()));
+assertEquals("[1, 2, 3]", vamh.invokeGeneric(1,2,3).toString());
+boolean failed = false;
+try { mh.invokeGeneric(1,2,3); }
+catch (WrongMethodTypeException ex) { failed = true; }
+assert(failed);
+ *
+ *
+ * @return true if this method handle accepts more than one arity of {@code invokeGeneric} calls
+ */
+ public boolean isVarargsCollector() {
+ return false;
+ }
+
+ /**
+ * Bind a value {@code x} to the first argument of a method handle, without invoking it.
+ * The new method handle adapts, as its target,
+ * to the current method handle.
* The type of the bound handle will be
* the same as the type of the target, except that a single leading
* reference parameter will be omitted.
@@ -619,74 +790,22 @@
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
- * Create a new method handle with the same type as this one,
- * but whose {@code asType} method invokes the given
- * {@code typeHandler} on this method handle,
- * instead of the standard {@code MethodHandles.convertArguments}.
- *
*
- * MethodHandle target = this; // original method handle
- * MethodHandle adapter = ...; // adapted method handle
- * MethodType requestedType = ...; // argument to asType()
- * if (type().equals(requestedType))
- * return adapter;
- * MethodHandle result = (MethodHandle)
- * typeHandler.invokeGeneric(target, requestedType);
- * if (!result.type().equals(requestedType))
- * throw new WrongMethodTypeException();
- * return result;
+ * "MethodHandle" + type().toString()
*
-MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
-MethodHandle asList = lookup()
- .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
-static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
- return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
-}
-MethodHandle collectingTypeHandler = lookup()
- .findStatic(lookup().lookupClass(), "collectingTypeHandler",
- methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
-MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
-
-assertEquals("[]", makeAnyList.invokeGeneric().toString());
-assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
-assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
- *
+ * Note: Future releases of this API may add further information
+ * to the string representation.
+ * Therefore, the present syntax should not be parsed by applications.
+ *
+ * @return a string representation of the method handle
*/
- public MethodHandle withTypeHandler(MethodHandle typeHandler) {
- return MethodHandles.withTypeHandler(this, typeHandler);
+ @Override
+ public String toString() {
+ return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
}
}
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/java/dyn/MethodHandles.java
--- a/jdk/src/share/classes/java/dyn/MethodHandles.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/java/dyn/MethodHandles.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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
@@ -135,7 +135,10 @@
*
- * {@link #insertArguments insertArguments}({@link #findVirtual findVirtual}(defc, name, type), receiver)
- *
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set
+ * and the trailing array argument is not the only argument.
+ * (If the trailing array argument is the only argument,
+ * the given receiver value will be bound to it.)
+ *
* where {@code defc} is either {@code receiver.getClass()} or a super
* type of that class, in which the requested method is accessible
* to the lookup class.
+ * (Note that {@code bindTo} does not preserve variable arity.)
* @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
@@ -568,7 +616,9 @@
MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
if (bmh == null)
throw newNoAccessException(method, lookupClass());
- return bmh;
+ if (dmh.type().parameterCount() == 0)
+ return dmh; // bound the trailing parameter; no varargs possible
+ return fixVarargs(bmh, dmh);
}
/**
@@ -581,6 +631,10 @@
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* If m is not public, do not share the resulting handle with untrusted parties.
+ *
+MethodHandle mh0 = {@link #findVirtual findVirtual}(defc, name, type);
+MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver);
+MethodType mt1 = mh1.type();
+if (mh0.isVarargsCollector() && mt1.parameterCount() > 0) {
+ mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
+return mh1;
+ *
* @param type the desired target type
* @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
* @return a method handle suitable for invoking any method handle of the given type
*/
static public
- MethodHandle varargsInvoker(MethodType type, int objectArgCount) {
+ MethodHandle spreadInvoker(MethodType type, int objectArgCount) {
if (objectArgCount < 0 || objectArgCount > type.parameterCount())
throw new IllegalArgumentException("bad argument count "+objectArgCount);
- return invokers(type).varargsInvoker(objectArgCount);
+ return invokers(type).spreadInvoker(objectArgCount);
}
/**
@@ -1826,7 +1889,10 @@
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
- * {@code target.invokeExact}.
+ * {@code target.invokeGeneric}.
+ * The target's type will be checked before the SAM
+ * instance is created, as if by a call to {@code asType},
+ * which may result in a {@code WrongMethodTypeException}.
*
- * MethodHandle invoker = lookup().findVirtual(MethodHandle.class, "invokeGeneric", type);
- * MethodType vaType = MethodType.genericMethodType(objectArgCount, true);
- * vaType = vaType.insertParameterType(0, MethodHandle.class);
- * int spreadArgCount = type.parameterCount - objectArgCount;
- * invoker = invoker.asSpreader(Object.class, spreadArgCount);
- * return invoker.asType(vaType);
+MethodHandle invoker = publicLookup()
+ .findVirtual(MethodHandle.class, "invokeGeneric", type)
+int spreadArgCount = type.parameterCount - objectArgCount;
+invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+return invoker;
*
*
+ * The last example assumes that the extra arguments are of type
+ * {@code CONSTANT_String} and {@code CONSTANT_Integer}, respectively.
+ * The second-to-last example assumes that all extra arguments are of type
+ * {@code CONSTANT_String}.
+ * The other examples work with all types of extra arguments.
*
*
*
+ * N sample bootstrap method
+ * * CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
+ * * CallSite bootstrap(Object... args)
* * CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)
+ * 0 CallSite bootstrap(Lookup caller, String name, MethodType type)
* 0 CallSite bootstrap(Lookup caller, Object... nameAndType)
* 1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
+ * 2 CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
+ * 2 CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
* 2 CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
Structure Summary
*
* // summary of constant and attribute structures
struct CONSTANT_MethodHandle_info {
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java
--- a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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
@@ -478,37 +478,60 @@
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
}
- static MethodHandle makeTypeHandler(Access token,
- MethodHandle target, MethodHandle typeHandler) {
+ static MethodHandle makeVarargsCollector(Access token,
+ MethodHandle target, Class> arrayType) {
Access.check(token);
- return new WithTypeHandler(target, typeHandler);
+ return new AsVarargsCollector(target, arrayType);
}
- static class WithTypeHandler extends AdapterMethodHandle {
- final MethodHandle target, typeHandler;
- WithTypeHandler(MethodHandle target, MethodHandle typeHandler) {
+ static class AsVarargsCollector extends AdapterMethodHandle {
+ final MethodHandle target;
+ final Class> arrayType;
+ MethodHandle cache;
+
+ AsVarargsCollector(MethodHandle target, Class> arrayType) {
super(target, target.type(), makeConv(OP_RETYPE_ONLY));
this.target = target;
- this.typeHandler = typeHandler.asType(TYPE_HANDLER_TYPE);
+ this.arrayType = arrayType;
+ this.cache = target.asCollector(arrayType, 0);
+ }
+
+ @Override
+ public boolean isVarargsCollector() {
+ return true;
}
+ @Override
public MethodHandle asType(MethodType newType) {
- if (this.type() == newType)
- return this;
+ MethodType type = this.type();
+ int collectArg = type.parameterCount() - 1;
+ int newArity = newType.parameterCount();
+ if (newArity == collectArg+1 &&
+ type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
+ // if arity and trailing parameter are compatible, do normal thing
+ return super.asType(newType);
+ }
+ // check cache
+ if (cache.type().parameterCount() == newArity)
+ return cache.asType(newType);
+ // build and cache a collector
+ int arrayLength = newArity - collectArg;
+ MethodHandle collector;
try {
- MethodHandle retyped = (MethodHandle) typeHandler.invokeExact(target, newType);
- // Contract: Must return the desired type, or throw WMT
- if (retyped.type() != newType)
- throw new WrongMethodTypeException(retyped.toString());
- return retyped;
- } catch (Throwable ex) {
- if (ex instanceof Error) throw (Error)ex;
- if (ex instanceof RuntimeException) throw (RuntimeException)ex;
- throw new RuntimeException(ex);
+ collector = target.asCollector(arrayType, arrayLength);
+ } catch (IllegalArgumentException ex) {
+ throw new WrongMethodTypeException("cannot build collector");
}
+ cache = collector;
+ return collector.asType(newType);
}
- private static final MethodType TYPE_HANDLER_TYPE
- = MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class);
+
+ public MethodHandle asVarargsCollector(Class> arrayType) {
+ MethodType type = this.type();
+ if (type.parameterType(type.parameterCount()-1) == arrayType)
+ return this;
+ return super.asVarargsCollector(arrayType);
+ }
}
/** Can a checkcast adapter validly convert the target to newType?
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/CallSiteImpl.java
--- a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java Fri Feb 11 01:26:24 2011 -0800
@@ -37,17 +37,17 @@
static CallSite makeSite(MethodHandle bootstrapMethod,
// Callee information:
String name, MethodType type,
- // Call-site attributes, if any:
+ // Extra arguments for BSM, if any:
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class> callerClass = callerMethod.getDeclaringClass();
Object caller;
- if (bootstrapMethod.type().parameterType(0) == Class.class)
+ if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD)
caller = callerClass; // remove for PFD
else
caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
- if (bootstrapMethod == null) {
+ if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) {
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
throw new IncompatibleClassChangeError
@@ -56,30 +56,35 @@
CallSite site;
try {
Object binding;
+ info = maybeReBox(info);
if (info == null) {
- if (false) // switch when invokeGeneric works
- binding = bootstrapMethod.invokeGeneric(caller, name, type);
- else
- binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
+ binding = bootstrapMethod.invokeGeneric(caller, name, type);
+ } else if (!info.getClass().isArray()) {
+ binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
} else {
- info = maybeReBox(info);
- if (false) // switch when invokeGeneric works
- binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
+ Object[] argv = (Object[]) info;
+ if (3 + argv.length > 255)
+ new InvokeDynamicBootstrapError("too many bootstrap method arguments");
+ MethodType bsmType = bootstrapMethod.type();
+ if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
+ binding = bootstrapMethod.invokeGeneric(caller, name, type, argv);
else
- binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type, info });
+ binding = MethodHandles.spreadInvoker(bsmType, 3)
+ .invokeGeneric(bootstrapMethod, caller, name, type, argv);
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
site = (CallSite) binding;
- } else if (binding instanceof MethodHandle) {
+ } else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) {
// Transitional!
MethodHandle target = (MethodHandle) binding;
site = new ConstantCallSite(target);
} else {
- throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
+ throw new ClassCastException("bootstrap method failed to produce a CallSite");
}
- PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
- callerMethod, callerBCI);
+ if (TRANSITIONAL_BEFORE_PFD)
+ PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
+ callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
@@ -93,6 +98,8 @@
return site;
}
+ private static boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD
+
private static Object maybeReBox(Object x) {
if (x instanceof Integer) {
int xi = (int) x;
@@ -117,6 +124,7 @@
static {
try {
PRIVATE_INITIALIZE_CALL_SITE =
+ !TRANSITIONAL_BEFORE_PFD ? null :
MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM",
MethodType.methodType(void.class,
String.class, MethodType.class,
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/InvokeGeneric.java
--- a/jdk/src/share/classes/sun/dyn/InvokeGeneric.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/InvokeGeneric.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. 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
@@ -108,7 +108,7 @@
*/
private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
MethodType targetType = target.type();
- if (USE_AS_TYPE_PATH || target instanceof AdapterMethodHandle.WithTypeHandler) {
+ if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/Invokers.java
--- a/jdk/src/share/classes/sun/dyn/Invokers.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/Invokers.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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
@@ -47,7 +47,7 @@
private /*lazy*/ MethodHandle genericInvoker;
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
- private final /*lazy*/ MethodHandle[] varargsInvokers;
+ private final /*lazy*/ MethodHandle[] spreadInvokers;
// invoker for an unbound callsite
private /*lazy*/ MethodHandle uninitializedCallSite;
@@ -55,10 +55,9 @@
/** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type.
*/
- public Invokers(Access token, MethodType targetType) {
- Access.check(token);
+ /*non-public*/ Invokers(MethodType targetType) {
this.targetType = targetType;
- this.varargsInvokers = new MethodHandle[targetType.parameterCount()+1];
+ this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
}
public static MethodType invokerType(MethodType targetType) {
@@ -69,7 +68,7 @@
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
try {
- invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType);
+ invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
} catch (NoAccessException ex) {
throw new InternalError("JVM cannot find invoker for "+targetType);
}
@@ -101,13 +100,13 @@
return invoker;
}
- public MethodHandle varargsInvoker(int objectArgCount) {
- MethodHandle vaInvoker = varargsInvokers[objectArgCount];
+ public MethodHandle spreadInvoker(int objectArgCount) {
+ MethodHandle vaInvoker = spreadInvokers[objectArgCount];
if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = genericInvoker();
MethodType vaType = MethodType.genericMethodType(objectArgCount, true);
vaInvoker = MethodHandles.spreadArguments(gInvoker, invokerType(vaType));
- varargsInvokers[objectArgCount] = vaInvoker;
+ spreadInvokers[objectArgCount] = vaInvoker;
return vaInvoker;
}
@@ -118,7 +117,7 @@
if (invoker != null) return invoker;
if (targetType.parameterCount() > 0) {
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
- Invokers invokers0 = MethodTypeImpl.invokers(Access.TOKEN, type0);
+ Invokers invokers0 = MethodTypeImpl.invokers(type0);
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
0, targetType.parameterList());
assert(invoker.type().equals(targetType));
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/MethodHandleImpl.java
--- a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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
@@ -184,7 +184,10 @@
if (!mh.isValid())
throw newNoAccessException(method, lookupClass);
assert(mh.type() == mtype);
- return mh;
+ if (!method.isVarargs())
+ return mh;
+ else
+ return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
}
public static
@@ -1263,8 +1266,8 @@
return MethodHandleNatives.getBootstrap(callerClass);
}
- public static MethodHandle withTypeHandler(Access token, MethodHandle target, MethodHandle typeHandler) {
+ public static MethodHandle asVarargsCollector(Access token, MethodHandle target, Class> arrayType) {
Access.check(token);
- return AdapterMethodHandle.makeTypeHandler(token, target, typeHandler);
+ return AdapterMethodHandle.makeVarargsCollector(token, target, arrayType);
}
}
diff -r c5df55701e91 -r 9e2483e6cfab jdk/src/share/classes/sun/dyn/MethodTypeImpl.java
--- a/jdk/src/share/classes/sun/dyn/MethodTypeImpl.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/src/share/classes/sun/dyn/MethodTypeImpl.java Fri Feb 11 01:26:24 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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
@@ -498,9 +498,12 @@
public static Invokers invokers(Access token, MethodType type) {
Access.check(token);
+ return invokers(type);
+ }
+ /*non-public*/ static Invokers invokers(MethodType type) {
Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
if (inv != null) return inv;
- inv = new Invokers(token, type);
+ inv = new Invokers(type);
METHOD_TYPE_FRIEND.setInvokers(type, inv);
return inv;
}
diff -r c5df55701e91 -r 9e2483e6cfab jdk/test/java/dyn/InvokeDynamicPrintArgs.java
--- a/jdk/test/java/dyn/InvokeDynamicPrintArgs.java Thu Feb 10 16:24:40 2011 -0800
+++ b/jdk/test/java/dyn/InvokeDynamicPrintArgs.java Fri Feb 11 01:26:24 2011 -0800
@@ -23,15 +23,19 @@
/* @test
* @summary smoke test for invokedynamic instructions
- * @library indify
+ * @build indify.Indify
* @compile InvokeDynamicPrintArgs.java
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic
* indify.Indify
* --verify-specifier-count=3 --transitionalJSR292=false
* --expand-properties --classpath ${test.classes}
- * --java InvokeDynamicPrintArgs --check-output
+ * --java test.java.dyn.InvokeDynamicPrintArgs --check-output
*/
+package test.java.dyn;
+
+import org.junit.Test;
+
import java.util.*;
import java.io.*;
@@ -53,6 +57,20 @@
closeBuf();
}
+ @Test
+ public void testInvokeDynamicPrintArgs() throws IOException {
+ System.err.println(System.getProperties());
+ String testClassPath = System.getProperty("build.test.classes.dir");
+ if (testClassPath == null) throw new RuntimeException();
+ String[] args = new String[]{
+ "--verify-specifier-count=3", "--transitionalJSR292=false",
+ "--expand-properties", "--classpath", testClassPath,
+ "--java", "test.java.dyn.InvokeDynamicPrintArgs", "--check-output"
+ };
+ System.err.println("Indify: "+Arrays.toString(args));
+ indify.Indify.main(args);
+ }
+
private static PrintStream oldOut;
private static ByteArrayOutputStream buf;
private static void openBuf() {
@@ -79,11 +97,11 @@
}
private static final String[] EXPECT_OUTPUT = {
"Printing some argument lists, starting with a empty one:",
- "[InvokeDynamicPrintArgs, nothing, ()void][]",
- "[InvokeDynamicPrintArgs, bar, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
- "[InvokeDynamicPrintArgs, bar2, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
- "[InvokeDynamicPrintArgs, baz, (java.lang.String,int,double)void, 1234.5][baz arg, 2, 3.14]",
- "[InvokeDynamicPrintArgs, foo, (java.lang.String)void][foo arg]",
+ "[test.java.dyn.InvokeDynamicPrintArgs, nothing, ()void][]",
+ "[test.java.dyn.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
+ "[test.java.dyn.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
+ "[test.java.dyn.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
+ "[test.java.dyn.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
"Done printing argument lists."
};
@@ -110,18 +128,15 @@
return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
}
- private static CallSite bsm2(Lookup caller, String name, MethodType type, Object arg) throws ReflectiveOperationException {
+ private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws ReflectiveOperationException {
// ignore caller and name, but match the type:
List