mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8150829: Enhanced drop-args, identity and default constant, varargs adjustment
Reviewed-by: psandoz, mhaupt, jrose
This commit is contained in:
parent
33a3b1cdf0
commit
284ec15fed
8 changed files with 490 additions and 66 deletions
|
@ -219,7 +219,8 @@ import static java.lang.invoke.MethodHandleStatics.*;
|
||||||
* Method handles produced by lookups or constant loads from methods or
|
* Method handles produced by lookups or constant loads from methods or
|
||||||
* constructors with the variable arity modifier bit ({@code 0x0080})
|
* constructors with the variable arity modifier bit ({@code 0x0080})
|
||||||
* have a corresponding variable arity, as if they were defined with
|
* have a corresponding variable arity, as if they were defined with
|
||||||
* the help of {@link #asVarargsCollector asVarargsCollector}.
|
* the help of {@link #asVarargsCollector asVarargsCollector}
|
||||||
|
* or {@link #withVarargs withVarargs}.
|
||||||
* <p>
|
* <p>
|
||||||
* A method reference may refer either to a static or non-static method.
|
* A method reference may refer either to a static or non-static method.
|
||||||
* In the non-static case, the method handle type includes an explicit
|
* In the non-static case, the method handle type includes an explicit
|
||||||
|
@ -972,6 +973,36 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
|
||||||
throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
|
throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Adapts this method handle to be {@linkplain #asVarargsCollector variable arity}
|
||||||
|
* if the boolean flag is true, else {@linkplain #asFixedArity fixed arity}.
|
||||||
|
* If the method handle is already of the proper arity mode, it is returned
|
||||||
|
* unchanged.
|
||||||
|
* @apiNote
|
||||||
|
* <p>This method is sometimes useful when adapting a method handle that
|
||||||
|
* may be variable arity, to ensure that the resulting adapter is also
|
||||||
|
* variable arity if and only if the original handle was. For example,
|
||||||
|
* this code changes the first argument of a handle {@code mh} to {@code int} without
|
||||||
|
* disturbing its variable arity property:
|
||||||
|
* {@code mh.asType(mh.type().changeParameterType(0,int.class))
|
||||||
|
* .withVarargs(mh.isVarargsCollector())}
|
||||||
|
* @param makeVarargs true if the return method handle should have variable arity behavior
|
||||||
|
* @return a method handle of the same type, with possibly adjusted variable arity behavior
|
||||||
|
* @throws IllegalArgumentException if {@code makeVarargs} is true and
|
||||||
|
* this method handle does not have a trailing array parameter
|
||||||
|
* @since 9
|
||||||
|
* @see #asVarargsCollector
|
||||||
|
* @see #asFixedArity
|
||||||
|
*/
|
||||||
|
public MethodHandle withVarargs(boolean makeVarargs) {
|
||||||
|
if (!makeVarargs) {
|
||||||
|
return asFixedArity();
|
||||||
|
} else if (!isVarargsCollector()) {
|
||||||
|
return asVarargsCollector(type().lastParameterType());
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
|
* Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
|
||||||
|
@ -1000,7 +1031,8 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
|
||||||
* to allow the target to use a simple {@code Object} as its last parameter type.)
|
* to allow the target to use a simple {@code Object} as its last parameter type.)
|
||||||
* <p>
|
* <p>
|
||||||
* In order to create a collecting adapter which is not restricted to a particular
|
* In order to create a collecting adapter which is not restricted to a particular
|
||||||
* number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
|
* number of collected arguments, use {@link #asVarargsCollector asVarargsCollector}
|
||||||
|
* or {@link #withVarargs withVarargs} instead.
|
||||||
* <p>
|
* <p>
|
||||||
* Here are some examples of array-collecting method handles:
|
* Here are some examples of array-collecting method handles:
|
||||||
* <blockquote><pre>{@code
|
* <blockquote><pre>{@code
|
||||||
|
@ -1216,7 +1248,7 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
|
||||||
* <p>
|
* <p>
|
||||||
* No method handle transformations produce new method handles with
|
* No method handle transformations produce new method handles with
|
||||||
* variable arity, unless they are documented as doing so.
|
* variable arity, unless they are documented as doing so.
|
||||||
* Therefore, besides {@code asVarargsCollector},
|
* Therefore, besides {@code asVarargsCollector} and {@code withVarargs},
|
||||||
* all methods in {@code MethodHandle} and {@code MethodHandles}
|
* all methods in {@code MethodHandle} and {@code MethodHandles}
|
||||||
* will return a method handle with fixed arity,
|
* will return a method handle with fixed arity,
|
||||||
* except in the cases where they are specified to return their original
|
* except in the cases where they are specified to return their original
|
||||||
|
@ -1273,6 +1305,7 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
|
||||||
* or {@code arrayType} is not assignable to this method handle's trailing parameter type
|
* or {@code arrayType} is not assignable to this method handle's trailing parameter type
|
||||||
* @see #asCollector
|
* @see #asCollector
|
||||||
* @see #isVarargsCollector
|
* @see #isVarargsCollector
|
||||||
|
* @see #withVarargs
|
||||||
* @see #asFixedArity
|
* @see #asFixedArity
|
||||||
*/
|
*/
|
||||||
public MethodHandle asVarargsCollector(Class<?> arrayType) {
|
public MethodHandle asVarargsCollector(Class<?> arrayType) {
|
||||||
|
@ -1344,6 +1377,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
||||||
* @return a new method handle which accepts only a fixed number of arguments
|
* @return a new method handle which accepts only a fixed number of arguments
|
||||||
* @see #asVarargsCollector
|
* @see #asVarargsCollector
|
||||||
* @see #isVarargsCollector
|
* @see #isVarargsCollector
|
||||||
|
* @see #withVarargs
|
||||||
*/
|
*/
|
||||||
public MethodHandle asFixedArity() {
|
public MethodHandle asFixedArity() {
|
||||||
assert(!isVarargsCollector());
|
assert(!isVarargsCollector());
|
||||||
|
@ -1428,11 +1462,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
||||||
/*non-public*/
|
/*non-public*/
|
||||||
MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
|
MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
|
||||||
if (!member.isVarargs()) return this;
|
if (!member.isVarargs()) return this;
|
||||||
Class<?> arrayType = type().lastParameterType();
|
try {
|
||||||
if (arrayType.isArray()) {
|
return this.withVarargs(true);
|
||||||
return MethodHandleImpl.makeVarargsCollector(this, arrayType);
|
} catch (IllegalArgumentException ex) {
|
||||||
|
throw member.makeAccessException("cannot make variable arity", null);
|
||||||
}
|
}
|
||||||
throw member.makeAccessException("cannot make variable arity", null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*non-public*/
|
/*non-public*/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -1055,7 +1055,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||||
if (!method.getInvocationType().equals(mh.type()))
|
if (!method.getInvocationType().equals(mh.type()))
|
||||||
throw new InternalError(method.toString());
|
throw new InternalError(method.toString());
|
||||||
mh = mh.withInternalMemberName(method, false);
|
mh = mh.withInternalMemberName(method, false);
|
||||||
mh = mh.asVarargsCollector(Object[].class);
|
mh = mh.withVarargs(true);
|
||||||
assert(method.isVarargs());
|
assert(method.isVarargs());
|
||||||
FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
|
FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
|
||||||
return mh;
|
return mh;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -216,13 +216,7 @@ public class MethodHandleProxies {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodHandle bindCaller(MethodHandle target, Class<?> hostClass) {
|
private static MethodHandle bindCaller(MethodHandle target, Class<?> hostClass) {
|
||||||
MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass);
|
return MethodHandleImpl.bindCaller(target, hostClass).withVarargs(target.isVarargsCollector());
|
||||||
if (target.isVarargsCollector()) {
|
|
||||||
MethodType type = cbmh.type();
|
|
||||||
int arity = type.parameterCount();
|
|
||||||
return cbmh.asVarargsCollector(type.parameterType(arity-1));
|
|
||||||
}
|
|
||||||
return cbmh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1352,9 +1352,7 @@ import static java.lang.invoke.MethodType.*;
|
||||||
...
|
...
|
||||||
MethodHandle mh0 = lookup().findVirtual(defc, name, type);
|
MethodHandle mh0 = lookup().findVirtual(defc, name, type);
|
||||||
MethodHandle mh1 = mh0.bindTo(receiver);
|
MethodHandle mh1 = mh0.bindTo(receiver);
|
||||||
MethodType mt1 = mh1.type();
|
mh1 = mh1.withVarargs(mh0.isVarargsCollector());
|
||||||
if (mh0.isVarargsCollector())
|
|
||||||
mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
|
|
||||||
return mh1;
|
return mh1;
|
||||||
* }</pre></blockquote>
|
* }</pre></blockquote>
|
||||||
* where {@code defc} is either {@code receiver.getClass()} or a super
|
* where {@code defc} is either {@code receiver.getClass()} or a super
|
||||||
|
@ -2951,9 +2949,55 @@ assert((int)twice.invokeExact(21) == 42);
|
||||||
if (ident.type().returnType() == type)
|
if (ident.type().returnType() == type)
|
||||||
return ident;
|
return ident;
|
||||||
// something like identity(Foo.class); do not bother to intern these
|
// something like identity(Foo.class); do not bother to intern these
|
||||||
assert(btw == Wrapper.OBJECT);
|
assert (btw == Wrapper.OBJECT);
|
||||||
return makeIdentity(type);
|
return makeIdentity(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a constant method handle of the requested return type which
|
||||||
|
* returns the default value for that type every time it is invoked.
|
||||||
|
* The resulting constant method handle will have no side effects.
|
||||||
|
* <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
|
||||||
|
* It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
|
||||||
|
* since {@code explicitCastArguments} converts {@code null} to default values.
|
||||||
|
* @param type the expected return type of the desired method handle
|
||||||
|
* @return a constant method handle that takes no arguments
|
||||||
|
* and returns the default value of the given type (or void, if the type is void)
|
||||||
|
* @throws NullPointerException if the argument is null
|
||||||
|
* @see MethodHandles#constant
|
||||||
|
* @see MethodHandles#empty
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public static MethodHandle zero(Class<?> type) {
|
||||||
|
Objects.requireNonNull(type);
|
||||||
|
return type.isPrimitive() ? zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandle identityOrVoid(Class<?> type) {
|
||||||
|
return type == void.class ? zero(type) : identity(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a method handle of the requested type which ignores any arguments, does nothing,
|
||||||
|
* and returns a suitable default depending on the return type.
|
||||||
|
* That is, it returns a zero primitive value, a {@code null}, or {@code void}.
|
||||||
|
* <p>The returned method handle is equivalent to
|
||||||
|
* {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
|
||||||
|
* <p>
|
||||||
|
* @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
|
||||||
|
* {@code guardWithTest(pred, target, empty(target.type())}.
|
||||||
|
* @param type the type of the desired method handle
|
||||||
|
* @return a constant method handle of the given type, which returns a default value of the given return type
|
||||||
|
* @throws NullPointerException if the argument is null
|
||||||
|
* @see MethodHandles#zero
|
||||||
|
* @see MethodHandles#constant
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public static MethodHandle empty(MethodType type) {
|
||||||
|
Objects.requireNonNull(type);
|
||||||
|
return dropArguments(zero(type.returnType()), 0, type.parameterList());
|
||||||
|
}
|
||||||
|
|
||||||
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
|
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
|
||||||
private static MethodHandle makeIdentity(Class<?> ptype) {
|
private static MethodHandle makeIdentity(Class<?> ptype) {
|
||||||
MethodType mtype = MethodType.methodType(ptype, ptype);
|
MethodType mtype = MethodType.methodType(ptype, ptype);
|
||||||
|
@ -3145,8 +3189,7 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
|
||||||
* If {@code pos} is zero, the dummy arguments will precede
|
* If {@code pos} is zero, the dummy arguments will precede
|
||||||
* the target's real arguments; if {@code pos} is <i>N</i>
|
* the target's real arguments; if {@code pos} is <i>N</i>
|
||||||
* they will come after.
|
* they will come after.
|
||||||
* <p>
|
* @apiNote
|
||||||
* <b>Example:</b>
|
|
||||||
* <blockquote><pre>{@code
|
* <blockquote><pre>{@code
|
||||||
import static java.lang.invoke.MethodHandles.*;
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
import static java.lang.invoke.MethodType.*;
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
@ -3185,6 +3228,99 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
|
||||||
return dropArguments(target, pos, Arrays.asList(valueTypes));
|
return dropArguments(target, pos, Arrays.asList(valueTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private version which allows caller some freedom with error handling
|
||||||
|
private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos,
|
||||||
|
boolean nullOnFailure) {
|
||||||
|
List<Class<?>> oldTypes = target.type().parameterList();
|
||||||
|
int match = oldTypes.size();
|
||||||
|
if (skip != 0) {
|
||||||
|
if (skip < 0 || skip > match) {
|
||||||
|
throw newIllegalArgumentException("illegal skip", skip, target);
|
||||||
|
}
|
||||||
|
oldTypes = oldTypes.subList(skip, match);
|
||||||
|
match -= skip;
|
||||||
|
}
|
||||||
|
List<Class<?>> addTypes = newTypes;
|
||||||
|
int add = addTypes.size();
|
||||||
|
if (pos != 0) {
|
||||||
|
if (pos < 0 || pos > add) {
|
||||||
|
throw newIllegalArgumentException("illegal pos", pos, newTypes);
|
||||||
|
}
|
||||||
|
addTypes = addTypes.subList(pos, add);
|
||||||
|
add -= pos; assert(addTypes.size() == add);
|
||||||
|
}
|
||||||
|
// Do not add types which already match the existing arguments.
|
||||||
|
if (match > add || !oldTypes.equals(addTypes.subList(0, match))) {
|
||||||
|
if (nullOnFailure) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw newIllegalArgumentException("argument lists do not match", oldTypes, newTypes);
|
||||||
|
}
|
||||||
|
addTypes = addTypes.subList(match, add);
|
||||||
|
add -= match; assert(addTypes.size() == add);
|
||||||
|
// newTypes: ( P*[pos], M*[match], A*[add] )
|
||||||
|
// target: ( S*[skip], M*[match] )
|
||||||
|
MethodHandle adapter = target;
|
||||||
|
if (add > 0) {
|
||||||
|
adapter = dropArguments(adapter, skip+ match, addTypes);
|
||||||
|
}
|
||||||
|
// adapter: (S*[skip], M*[match], A*[add] )
|
||||||
|
if (pos > 0) {
|
||||||
|
adapter = dropArguments(adapter, skip, newTypes.subList(0, pos));
|
||||||
|
}
|
||||||
|
// adapter: (S*[skip], P*[pos], M*[match], A*[add] )
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts a target method handle to match the given parameter type list, if necessary, by adding dummy arguments.
|
||||||
|
* Some leading parameters are first skipped; they will be left unchanged and are otherwise ignored.
|
||||||
|
* The remaining types in the target's parameter type list must be contained as a sub-list of the given type list,
|
||||||
|
* at the given position.
|
||||||
|
* Any non-matching parameter types (before or after the matching sub-list) are inserted in corresponding
|
||||||
|
* positions of the target method handle's parameters, as if by {@link #dropArguments}.
|
||||||
|
* (More precisely, elements in the new list before {@code pos} are inserted into the target list at {@code skip},
|
||||||
|
* while elements in the new list after the match beginning at {@code pos} are inserted at the end of the
|
||||||
|
* target list.)
|
||||||
|
* The target's return type will be unchanged.
|
||||||
|
* @apiNote
|
||||||
|
* Two method handles whose argument lists are "effectively identical" (i.e., identical
|
||||||
|
* in a common prefix) may be mutually converted to a common type
|
||||||
|
* by two calls to {@code dropArgumentsToMatch}, as follows:
|
||||||
|
* <blockquote><pre>{@code
|
||||||
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
...
|
||||||
|
...
|
||||||
|
MethodHandle h0 = constant(boolean.class, true);
|
||||||
|
MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);
|
||||||
|
MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());
|
||||||
|
if (h1.type().parameterCount() < h2.type().parameterCount())
|
||||||
|
h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1
|
||||||
|
else
|
||||||
|
h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2
|
||||||
|
MethodHandle h3 = guardWithTest(h0, h1, h2);
|
||||||
|
assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
|
||||||
|
* }</pre></blockquote>
|
||||||
|
* @param target the method handle to adapt
|
||||||
|
* @param skip number of targets parameters to disregard (they will be unchanged)
|
||||||
|
* @param newTypes the desired argument list of the method handle
|
||||||
|
* @param pos place in {@code newTypes} where the non-skipped target parameters must occur
|
||||||
|
* @return a possibly adapted method handle
|
||||||
|
* @throws NullPointerException if either argument is null
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if either index is out of range in its corresponding list, or
|
||||||
|
* if the non-skipped target parameter types match the new types at {@code pos}
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos) {
|
||||||
|
Objects.requireNonNull(target);
|
||||||
|
Objects.requireNonNull(newTypes);
|
||||||
|
return dropArgumentsToMatch(target, skip, newTypes, pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapts a target method handle by pre-processing
|
* Adapts a target method handle by pre-processing
|
||||||
* one or more of its arguments, each with its own unary filter function,
|
* one or more of its arguments, each with its own unary filter function,
|
||||||
|
@ -3696,13 +3832,9 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
if (gtype.returnType() != boolean.class)
|
if (gtype.returnType() != boolean.class)
|
||||||
throw newIllegalArgumentException("guard type is not a predicate "+gtype);
|
throw newIllegalArgumentException("guard type is not a predicate "+gtype);
|
||||||
List<Class<?>> targs = ttype.parameterList();
|
List<Class<?>> targs = ttype.parameterList();
|
||||||
List<Class<?>> gargs = gtype.parameterList();
|
test = dropArgumentsToMatch(test, 0, targs, 0, true);
|
||||||
if (!targs.equals(gargs)) {
|
if (test == null) {
|
||||||
int gpc = gargs.size(), tpc = targs.size();
|
throw misMatchedTypes("target and test types", ttype, gtype);
|
||||||
if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
|
|
||||||
throw misMatchedTypes("target and test types", ttype, gtype);
|
|
||||||
test = dropArguments(test, gpc, targs.subList(gpc, tpc));
|
|
||||||
gtype = test.type();
|
|
||||||
}
|
}
|
||||||
return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
|
return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
|
||||||
}
|
}
|
||||||
|
@ -3774,15 +3906,9 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
throw newIllegalArgumentException("handler does not accept exception type "+exType);
|
throw newIllegalArgumentException("handler does not accept exception type "+exType);
|
||||||
if (htype.returnType() != ttype.returnType())
|
if (htype.returnType() != ttype.returnType())
|
||||||
throw misMatchedTypes("target and handler return types", ttype, htype);
|
throw misMatchedTypes("target and handler return types", ttype, htype);
|
||||||
List<Class<?>> targs = ttype.parameterList();
|
handler = dropArgumentsToMatch(handler, 1, ttype.parameterList(), 0, true);
|
||||||
List<Class<?>> hargs = htype.parameterList();
|
if (handler == null) {
|
||||||
hargs = hargs.subList(1, hargs.size()); // omit leading parameter from handler
|
throw misMatchedTypes("target and handler types", ttype, htype);
|
||||||
if (!targs.equals(hargs)) {
|
|
||||||
int hpc = hargs.size(), tpc = targs.size();
|
|
||||||
if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
|
|
||||||
throw misMatchedTypes("target and handler types", ttype, htype);
|
|
||||||
handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
|
|
||||||
htype = handler.type();
|
|
||||||
}
|
}
|
||||||
return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
|
return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
|
||||||
}
|
}
|
||||||
|
@ -4040,16 +4166,16 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
for (int i = 0; i < nclauses; ++i) {
|
for (int i = 0; i < nclauses; ++i) {
|
||||||
Class<?> t = iterationVariableTypes.get(i);
|
Class<?> t = iterationVariableTypes.get(i);
|
||||||
if (init.get(i) == null) {
|
if (init.get(i) == null) {
|
||||||
init.set(i, zeroHandle(t));
|
init.set(i, empty(MethodType.methodType(t, commonSuffix)));
|
||||||
}
|
}
|
||||||
if (step.get(i) == null) {
|
if (step.get(i) == null) {
|
||||||
step.set(i, dropArguments(t == void.class ? zeroHandle(t) : identity(t), 0, commonPrefix.subList(0, i)));
|
step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i));
|
||||||
}
|
}
|
||||||
if (pred.get(i) == null) {
|
if (pred.get(i) == null) {
|
||||||
pred.set(i, constant(boolean.class, true));
|
pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence));
|
||||||
}
|
}
|
||||||
if (fini.get(i) == null) {
|
if (fini.get(i) == null) {
|
||||||
fini.set(i, zeroHandle(t));
|
fini.set(i, empty(MethodType.methodType(t, commonParameterSequence)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4143,7 +4269,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
|
public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
|
||||||
MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
|
MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType());
|
||||||
MethodHandle[] checkExit = {null, null, pred, fin};
|
MethodHandle[] checkExit = {null, null, pred, fin};
|
||||||
MethodHandle[] varBody = {init, body};
|
MethodHandle[] varBody = {init, body};
|
||||||
return loop(checkExit, varBody);
|
return loop(checkExit, varBody);
|
||||||
|
@ -4209,7 +4335,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
|
public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
|
||||||
MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
|
MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType());
|
||||||
MethodHandle[] clause = {init, body, pred, fin};
|
MethodHandle[] clause = {init, body, pred, fin};
|
||||||
return loop(clause);
|
return loop(clause);
|
||||||
}
|
}
|
||||||
|
@ -4346,7 +4472,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
|
public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
|
||||||
MethodHandle returnVar = dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()),
|
MethodHandle returnVar = dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()),
|
||||||
0, int.class, int.class);
|
0, int.class, int.class);
|
||||||
MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
|
MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
|
||||||
MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
|
MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
|
||||||
|
@ -4449,7 +4575,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
Class<?> ttype = body.type().parameterType(0);
|
Class<?> ttype = body.type().parameterType(0);
|
||||||
|
|
||||||
MethodHandle returnVar =
|
MethodHandle returnVar =
|
||||||
dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()), 0, itype);
|
dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), 0, itype);
|
||||||
MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
|
MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
|
||||||
MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
|
MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
|
||||||
|
|
||||||
|
@ -4543,15 +4669,11 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
checkTryFinally(target, cleanup);
|
checkTryFinally(target, cleanup);
|
||||||
|
|
||||||
// Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
|
// Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
|
||||||
int tpSize = targetParamTypes.size();
|
// The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
|
||||||
int cpPrefixLength = rtype == void.class ? 1 : 2;
|
// target parameter list.
|
||||||
int cpSize = cleanupParamTypes.size();
|
cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0);
|
||||||
MethodHandle aCleanup = cpSize - cpPrefixLength < tpSize ?
|
|
||||||
dropArguments(cleanup, cpSize, targetParamTypes.subList(tpSize - (cpSize - cpPrefixLength), tpSize)) :
|
|
||||||
cleanup;
|
|
||||||
|
|
||||||
MethodHandle aTarget = target.asSpreader(Object[].class, target.type().parameterCount());
|
MethodHandle aTarget = target.asSpreader(Object[].class, target.type().parameterCount());
|
||||||
aCleanup = aCleanup.asSpreader(Object[].class, tpSize);
|
MethodHandle aCleanup = cleanup.asSpreader(Object[].class, targetParamTypes.size());
|
||||||
|
|
||||||
return MethodHandleImpl.makeTryFinally(aTarget, aCleanup, rtype, targetParamTypes);
|
return MethodHandleImpl.makeTryFinally(aTarget, aCleanup, rtype, targetParamTypes);
|
||||||
}
|
}
|
||||||
|
@ -4642,16 +4764,6 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap creation of a proper zero handle for a given type.
|
|
||||||
*
|
|
||||||
* @param type the type.
|
|
||||||
*
|
|
||||||
* @return a zero value for the given type.
|
|
||||||
*/
|
|
||||||
static MethodHandle zeroHandle(Class<?> type) {
|
|
||||||
return type.isPrimitive() ? zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkLoop0(MethodHandle[][] clauses) {
|
private static void checkLoop0(MethodHandle[][] clauses) {
|
||||||
if (clauses == null || clauses.length == 0) {
|
if (clauses == null || clauses.length == 0) {
|
||||||
|
|
83
jdk/test/java/lang/invoke/ConstantIdentityMHTest.java
Normal file
83
jdk/test/java/lang/invoke/ConstantIdentityMHTest.java
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary unit tests for java.lang.invoke.MethodHandles
|
||||||
|
* @run testng/othervm -ea -esa test.java.lang.invoke.ConstantIdentityMHTest
|
||||||
|
*/
|
||||||
|
package test.java.lang.invoke;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
import static org.testng.AssertJUnit.*;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
public class ConstantIdentityMHTest {
|
||||||
|
|
||||||
|
@DataProvider(name = "testZeroData")
|
||||||
|
private Object[][] testZeroData() {
|
||||||
|
return new Object[][] {
|
||||||
|
{void.class, "()void"},
|
||||||
|
{int.class, "()int"},
|
||||||
|
{byte.class, "()byte"},
|
||||||
|
{short.class, "()short"},
|
||||||
|
{long.class, "()long"},
|
||||||
|
{float.class, "()float"},
|
||||||
|
{double.class, "()double"},
|
||||||
|
{boolean.class, "()boolean"},
|
||||||
|
{char.class, "()char"},
|
||||||
|
{Integer.class, "()Integer"}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "testZeroData")
|
||||||
|
public void testZero(Class<?> expectedtype, String expected) throws Throwable {
|
||||||
|
assertEquals(MethodHandles.zero(expectedtype).type().toString(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ExpectedExceptions(NullPointerException.class)
|
||||||
|
public void testZeroNPE() {
|
||||||
|
MethodHandle mh = MethodHandles.zero(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEmpty() throws Throwable {
|
||||||
|
MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
assertEquals("xy", (String)cat.invoke("x","y"));
|
||||||
|
MethodHandle mhEmpty = MethodHandles.empty(cat.type());
|
||||||
|
assertEquals(null, (String)mhEmpty.invoke("x","y"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ExpectedExceptions(NullPointerException.class)
|
||||||
|
void testEmptyNPE() {
|
||||||
|
MethodHandle lenEmptyMH = MethodHandles.empty(null);
|
||||||
|
}
|
||||||
|
}
|
90
jdk/test/java/lang/invoke/DropArgumentsTest.java
Normal file
90
jdk/test/java/lang/invoke/DropArgumentsTest.java
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary unit tests for java.lang.invoke.MethodHandles
|
||||||
|
* @run testng/othervm -ea -esa test.java.lang.invoke.DropArgumentsTest
|
||||||
|
*/
|
||||||
|
package test.java.lang.invoke;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.List;
|
||||||
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
import static org.testng.AssertJUnit.*;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
public class DropArgumentsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDropArgumentsToMatch() throws Throwable {
|
||||||
|
MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
MethodType bigType = cat.type().insertParameterTypes(0, String.class, String.class, int.class);
|
||||||
|
MethodHandle d0 = MethodHandles.dropArgumentsToMatch(cat, 0, bigType.parameterList(), 3);
|
||||||
|
assertEquals("xy",(String)d0.invokeExact("m", "n", 1, "x", "y"));
|
||||||
|
MethodHandle d1 = MethodHandles.dropArgumentsToMatch(cat, 0, bigType.parameterList(), 0);
|
||||||
|
assertEquals("mn",(String)d1.invokeExact("m", "n", 1, "x", "y"));
|
||||||
|
MethodHandle d2 = MethodHandles.dropArgumentsToMatch(cat, 1, bigType.parameterList(), 4);
|
||||||
|
assertEquals("xy",(String)d2.invokeExact("x", "b", "c", 1, "a", "y"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataProvider(name = "dropArgumentsToMatchNPEData")
|
||||||
|
private Object[][] dropArgumentsToMatchNPEData()
|
||||||
|
throws NoSuchMethodException, IllegalAccessException {
|
||||||
|
MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
return new Object[][] {
|
||||||
|
{ (MethodHandle) null, 0, cat.type().parameterList(), 0 },
|
||||||
|
{ cat, 0, null, 0 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "dropArgumentsToMatchNPEData")
|
||||||
|
@ExpectedExceptions(NullPointerException.class)
|
||||||
|
public void dropArgumentsToMatchNPE(MethodHandle target, int pos, List<Class<?>> valueType, int skip) {
|
||||||
|
MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataProvider(name = "dropArgumentsToMatchIAEData")
|
||||||
|
private Object[][] dropArgumentsToMatchIAEData()
|
||||||
|
throws NoSuchMethodException, IllegalAccessException {
|
||||||
|
MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
MethodType bigType = cat.type().insertParameterTypes(0, String.class, String.class, int.class);
|
||||||
|
return new Object[][] {
|
||||||
|
{cat, -1, bigType.parameterList(), 0},
|
||||||
|
{cat, 0, bigType.parameterList(), -1},
|
||||||
|
{cat, 3, bigType.parameterList(), 0},
|
||||||
|
{cat, 0, bigType.parameterList(), 2}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "dropArgumentsToMatchIAEData")
|
||||||
|
@ExpectedExceptions(IllegalArgumentException.class)
|
||||||
|
public void dropArgumentsToMatchIAE(MethodHandle target, int pos, List<Class<?>> valueType, int skip) {
|
||||||
|
MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -57,7 +57,9 @@ public class JavaDocExamplesTest {
|
||||||
testFindVirtual();
|
testFindVirtual();
|
||||||
testFindSpecial();
|
testFindSpecial();
|
||||||
testPermuteArguments();
|
testPermuteArguments();
|
||||||
|
testZero();
|
||||||
testDropArguments();
|
testDropArguments();
|
||||||
|
testDropArgumentsToMatch();
|
||||||
testFilterArguments();
|
testFilterArguments();
|
||||||
testFoldArguments();
|
testFoldArguments();
|
||||||
testFoldArguments2();
|
testFoldArguments2();
|
||||||
|
@ -235,6 +237,17 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testZero() throws Throwable {
|
||||||
|
{{
|
||||||
|
{} /// JAVADOC
|
||||||
|
Class<?> type = Double.class;
|
||||||
|
MethodHandle mh1 = MethodHandles.explicitCastArguments(MethodHandles.constant(Object.class, null), methodType(type));
|
||||||
|
assertEquals("()Double", mh1.type().toString());
|
||||||
|
MethodHandle mh2 = MethodHandles.empty(methodType(type));
|
||||||
|
assertEquals("()Double", mh2.type().toString());
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void testDropArguments() throws Throwable {
|
@Test public void testDropArguments() throws Throwable {
|
||||||
{{
|
{{
|
||||||
{} /// JAVADOC
|
{} /// JAVADOC
|
||||||
|
@ -262,6 +275,24 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testDropArgumentsToMatch() throws Throwable {
|
||||||
|
{{
|
||||||
|
{} /// JAVADOC
|
||||||
|
MethodHandle h0= constant(boolean.class, true);
|
||||||
|
MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
|
||||||
|
MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);
|
||||||
|
MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());
|
||||||
|
if (h1.type().parameterCount() < h2.type().parameterCount()) {
|
||||||
|
h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2
|
||||||
|
}
|
||||||
|
MethodHandle h3 = guardWithTest(h0, h1, h2);
|
||||||
|
assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void testFilterArguments() throws Throwable {
|
@Test public void testFilterArguments() throws Throwable {
|
||||||
{{
|
{{
|
||||||
{} /// JAVADOC
|
{} /// JAVADOC
|
||||||
|
|
80
jdk/test/java/lang/invoke/VarArgsTest.java
Normal file
80
jdk/test/java/lang/invoke/VarArgsTest.java
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary unit tests for java.lang.invoke.MethodHandles
|
||||||
|
* @run testng/othervm -ea -esa test.java.lang.invoke.VarArgsTest
|
||||||
|
*/
|
||||||
|
package test.java.lang.invoke;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
import static org.testng.AssertJUnit.*;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
public class VarArgsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithVarargs() throws Throwable {
|
||||||
|
MethodHandle deepToString = publicLookup()
|
||||||
|
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
|
||||||
|
assertFalse(deepToString.isVarargsCollector());
|
||||||
|
MethodHandle ts = deepToString.withVarargs(false);
|
||||||
|
assertFalse(ts.isVarargsCollector());
|
||||||
|
MethodHandle ts1 = deepToString.withVarargs(true);
|
||||||
|
assertTrue(ts1.isVarargsCollector());
|
||||||
|
assertEquals("[won]", (String) ts1.invokeExact(new Object[]{"won"}));
|
||||||
|
assertEquals("[won]", (String) ts1.invoke(new Object[]{"won"}));
|
||||||
|
assertEquals("[won]", (String) ts1.invoke("won"));
|
||||||
|
assertEquals("[won, won]", (String) ts1.invoke("won", "won"));
|
||||||
|
assertEquals("[won, won]", (String) ts1.invoke(new Object[]{"won", "won"}));
|
||||||
|
assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithVarargs2() throws Throwable {
|
||||||
|
MethodHandle asList = publicLookup()
|
||||||
|
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
|
||||||
|
MethodHandle asListWithVarargs = asList.withVarargs(asList.isVarargsCollector());
|
||||||
|
assert(asListWithVarargs.isVarargsCollector());
|
||||||
|
assertEquals("[]", asListWithVarargs.invoke().toString());
|
||||||
|
assertEquals("[1]", asListWithVarargs.invoke(1).toString());
|
||||||
|
assertEquals("[two, too]", asListWithVarargs.invoke("two", "too").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ExpectedExceptions(IllegalArgumentException.class)
|
||||||
|
public void testWithVarargsIAE() throws Throwable {
|
||||||
|
MethodHandle lenMH = publicLookup()
|
||||||
|
.findVirtual(String.class, "length", methodType(int.class));
|
||||||
|
MethodHandle lenMHWithVarargs = lenMH.withVarargs(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue