提交 a7fbe030 编写于 作者: T trims

Merge

...@@ -141,7 +141,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -141,7 +141,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
while (lastConv >= 0) { while (lastConv >= 0) {
Class<?> src = newType.parameterType(lastConv); // source type Class<?> src = newType.parameterType(lastConv); // source type
Class<?> dst = oldType.parameterType(lastConv); // destination type Class<?> dst = oldType.parameterType(lastConv); // destination type
if (VerifyType.isNullConversion(src, dst)) { if (isTrivialConversion(src, dst, level)) {
--lastConv; --lastConv;
} else { } else {
break; break;
...@@ -150,7 +150,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -150,7 +150,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class<?> needReturn = newType.returnType(); Class<?> needReturn = newType.returnType();
Class<?> haveReturn = oldType.returnType(); Class<?> haveReturn = oldType.returnType();
boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn); boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
// Now build a chain of one or more adapters. // Now build a chain of one or more adapters.
MethodHandle adapter = target, adapter2; MethodHandle adapter = target, adapter2;
...@@ -158,7 +158,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -158,7 +158,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
for (int i = 0; i <= lastConv; i++) { for (int i = 0; i <= lastConv; i++) {
Class<?> src = newType.parameterType(i); // source type Class<?> src = newType.parameterType(i); // source type
Class<?> dst = midType.parameterType(i); // destination type Class<?> dst = midType.parameterType(i); // destination type
if (VerifyType.isNullConversion(src, dst)) { if (isTrivialConversion(src, dst, level)) {
// do nothing: difference is trivial // do nothing: difference is trivial
continue; continue;
} }
...@@ -219,6 +219,22 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -219,6 +219,22 @@ class AdapterMethodHandle extends BoundMethodHandle {
return adapter; return adapter;
} }
private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) {
if (src == dst || dst == void.class) return true;
if (!VerifyType.isNullConversion(src, dst)) return false;
if (level > 1) return true; // explicitCastArguments
boolean sp = src.isPrimitive();
boolean dp = dst.isPrimitive();
if (sp != dp) return false;
if (sp) {
// in addition to being a null conversion, forbid boolean->int etc.
return Wrapper.forPrimitiveType(dst)
.isConvertibleFrom(Wrapper.forPrimitiveType(src));
} else {
return dst.isAssignableFrom(src);
}
}
private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) { private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) {
MethodHandle adjustReturn; MethodHandle adjustReturn;
if (haveReturn == void.class) { if (haveReturn == void.class) {
...@@ -530,6 +546,10 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -530,6 +546,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
} }
static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
MethodType type = target.type();
int last = type.parameterCount() - 1;
if (type.parameterType(last) != arrayType)
target = target.asType(type.changeParameterType(last, arrayType));
return new AsVarargsCollector(target, arrayType); return new AsVarargsCollector(target, arrayType);
} }
...@@ -596,7 +616,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -596,7 +616,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
|| !VerifyType.isNullConversion(castType, dst)) || !VerifyType.isNullConversion(castType, dst))
return false; return false;
int diff = diffTypes(newType, targetType, false); int diff = diffTypes(newType, targetType, false);
return (diff == arg+1); // arg is sole non-trivial diff return (diff == arg+1) || (diff == 0); // arg is sole non-trivial diff
} }
/** Can an primitive conversion adapter validly convert src to dst? */ /** Can an primitive conversion adapter validly convert src to dst? */
static boolean canCheckCast(Class<?> src, Class<?> dst) { static boolean canCheckCast(Class<?> src, Class<?> dst) {
...@@ -1033,8 +1053,9 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -1033,8 +1053,9 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
// FIXME: Get rid of newType; derive new arguments from structure of spreadArgType // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
MethodType targetType = target.type(); MethodType targetType = target.type();
if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
return null; : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
+ Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount);
// dest is not significant; remove? // dest is not significant; remove?
int dest = T_VOID; int dest = T_VOID;
for (int i = 0; i < spreadArgCount; i++) { for (int i = 0; i < spreadArgCount; i++) {
...@@ -1127,7 +1148,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -1127,7 +1148,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
} }
@Override @Override
public String toString() { String debugString() {
return getNameString(nonAdapter((MethodHandle)vmtarget), this); return getNameString(nonAdapter((MethodHandle)vmtarget), this);
} }
......
...@@ -155,7 +155,7 @@ class BoundMethodHandle extends MethodHandle { ...@@ -155,7 +155,7 @@ class BoundMethodHandle extends MethodHandle {
} }
@Override @Override
public String toString() { String debugString() {
return addTypeString(baseName(), this); return addTypeString(baseName(), this);
} }
......
...@@ -234,7 +234,7 @@ class FilterGeneric { ...@@ -234,7 +234,7 @@ class FilterGeneric {
protected final MethodHandle target; // ultimate target protected final MethodHandle target; // ultimate target
@Override @Override
public String toString() { String debugString() {
return addTypeString(target, this); return addTypeString(target, this);
} }
......
...@@ -41,7 +41,7 @@ class FilterOneArgument extends BoundMethodHandle { ...@@ -41,7 +41,7 @@ class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle target; // Object -> Object protected final MethodHandle target; // Object -> Object
@Override @Override
public String toString() { String debugString() {
return target.toString(); return target.toString();
} }
......
...@@ -260,7 +260,7 @@ class FromGeneric { ...@@ -260,7 +260,7 @@ class FromGeneric {
protected final MethodHandle target; // (any**N) => R protected final MethodHandle target; // (any**N) => R
@Override @Override
public String toString() { String debugString() {
return addTypeString(target, this); return addTypeString(target, this);
} }
......
...@@ -129,20 +129,17 @@ class InvokeGeneric { ...@@ -129,20 +129,17 @@ class InvokeGeneric {
if (needType == erasedCallerType.returnType()) if (needType == erasedCallerType.returnType())
return false; // no conversions possible, since must be primitive or Object return false; // no conversions possible, since must be primitive or Object
Class<?> haveType = target.type().returnType(); Class<?> haveType = target.type().returnType();
if (VerifyType.isNullConversion(haveType, needType)) if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
return false; return false;
return true; return true;
} }
private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) { private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
if (true) throw new RuntimeException("NYI");
// FIXME: This is slow because it creates a closure node on every call that requires a return cast. // FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType targetType = target.type(); MethodType finisherType = finisher.type();
MethodHandle caster = ValueConversions.identity(type); MethodHandle caster = ValueConversions.identity(type);
caster = caster.asType(MethodType.methodType(type, targetType.returnType())); caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
// Drop irrelevant arguments, because we only care about the return value: finisher = MethodHandles.filterReturnValue(finisher, caster);
caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList()); return finisher.asType(finisherType);
MethodHandle result = MethodHandles.foldArguments(caster, target);
return result.asType(target.type());
} }
public String toString() { public String toString() {
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package java.lang.invoke; package java.lang.invoke;
import java.util.ArrayList;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
...@@ -708,9 +709,9 @@ public abstract class MethodHandle { ...@@ -708,9 +709,9 @@ public abstract class MethodHandle {
*/ */
public MethodHandle asType(MethodType newType) { public MethodHandle asType(MethodType newType) {
if (!type.isConvertibleTo(newType)) { if (!type.isConvertibleTo(newType)) {
throw new WrongMethodTypeException("cannot convert "+type+" to "+newType); throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
} }
return MethodHandles.convertArguments(this, newType); return MethodHandleImpl.convertArguments(this, newType, 1);
} }
/** /**
...@@ -750,11 +751,46 @@ public abstract class MethodHandle { ...@@ -750,11 +751,46 @@ public abstract class MethodHandle {
* @see #asCollector * @see #asCollector
*/ */
public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) { public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
Class<?> arrayElement = arrayType.getComponentType(); asSpreaderChecks(arrayType, arrayLength);
if (arrayElement == null) throw newIllegalArgumentException("not an array type"); return MethodHandleImpl.spreadArguments(this, arrayType, arrayLength);
}
private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount(); int nargs = type().parameterCount();
if (nargs < arrayLength) throw newIllegalArgumentException("bad spread array length"); if (nargs < arrayLength) throw newIllegalArgumentException("bad spread array length");
return MethodHandleImpl.spreadArguments(this, arrayType, arrayLength); if (arrayType != Object[].class && arrayLength != 0) {
boolean sawProblem = false;
Class<?> arrayElement = arrayType.getComponentType();
for (int i = nargs - arrayLength; i < nargs; i++) {
if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
sawProblem = true;
break;
}
}
if (sawProblem) {
ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>(type().parameterList());
for (int i = nargs - arrayLength; i < nargs; i++) {
ptypes.set(i, arrayElement);
}
// elicit an error:
this.asType(MethodType.methodType(type().returnType(), ptypes));
}
}
}
private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
Class<?> arrayElement = arrayType.getComponentType();
if (arrayElement == null)
throw newIllegalArgumentException("not an array type", arrayType);
if ((arrayLength & 0x7F) != arrayLength) {
if ((arrayLength & 0xFF) != arrayLength)
throw newIllegalArgumentException("array length is not legal", arrayLength);
assert(arrayLength >= 128);
if (arrayElement == long.class ||
arrayElement == double.class)
throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
}
} }
/** /**
...@@ -802,10 +838,8 @@ public abstract class MethodHandle { ...@@ -802,10 +838,8 @@ public abstract class MethodHandle {
return MethodHandleImpl.collectArguments(this, type.parameterCount()-1, collector); return MethodHandleImpl.collectArguments(this, type.parameterCount()-1, collector);
} }
private void asCollectorChecks(Class<?> arrayType, int arrayLength) { private void asCollectorChecks(Class<?> arrayType, int arrayLength) {
Class<?> arrayElement = arrayType.getComponentType(); spreadArrayChecks(arrayType, arrayLength);
if (arrayElement == null)
throw newIllegalArgumentException("not an array type", arrayType);
int nargs = type().parameterCount(); int nargs = type().parameterCount();
if (nargs == 0 || !type().parameterType(nargs-1).isAssignableFrom(arrayType)) if (nargs == 0 || !type().parameterType(nargs-1).isAssignableFrom(arrayType))
throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType); throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
...@@ -965,8 +999,8 @@ assert(failed); ...@@ -965,8 +999,8 @@ assert(failed);
*/ */
public MethodHandle asVarargsCollector(Class<?> arrayType) { public MethodHandle asVarargsCollector(Class<?> arrayType) {
Class<?> arrayElement = arrayType.getComponentType(); Class<?> arrayElement = arrayType.getComponentType();
if (arrayElement == null) throw newIllegalArgumentException("not an array type"); asCollectorChecks(arrayType, 0);
return MethodHandles.asVarargsCollector(this, arrayType); return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
} }
/** /**
...@@ -1043,6 +1077,12 @@ assert(failed); ...@@ -1043,6 +1077,12 @@ assert(failed);
*/ */
@Override @Override
public String toString() { public String toString() {
if (DEBUG_METHOD_HANDLE_NAMES) return debugString();
return "MethodHandle"+type;
}
/*non-public*/
String debugString() {
return getNameString(this); return getNameString(this);
} }
} }
...@@ -93,9 +93,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -93,9 +93,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static static
MethodHandle makeAllocator(MethodHandle rawConstructor) { MethodHandle makeAllocator(MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type(); MethodType rawConType = rawConstructor.type();
Class<?> allocateClass = rawConType.parameterType(0);
// Wrap the raw (unsafe) constructor with the allocation of a suitable object. // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
if (AdapterMethodHandle.canCollectArguments(rawConType, MethodType.methodType(allocateClass), 0, true)) {
// allocator(arg...)
// [fold]=> cookedConstructor(obj=allocate(C), arg...)
// [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
MethodHandle returner = MethodHandles.identity(allocateClass);
MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
MethodHandle cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
assert(cookedConstructor.type().equals(ctype));
ctype = ctype.dropParameterTypes(0, 1);
cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
MethodHandle allocator = new AllocateObject(allocateClass);
// allocate() => new C(void)
assert(allocator.type().equals(MethodType.methodType(allocateClass)));
ctype = ctype.dropParameterTypes(0, 1);
MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
return fold;
}
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle allocator MethodHandle allocator
= AllocateObject.make(rawConType.parameterType(0), rawConstructor); = AllocateObject.make(allocateClass, rawConstructor);
assert(allocator.type() assert(allocator.type()
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0)))); .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
return allocator; return allocator;
...@@ -112,8 +131,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -112,8 +131,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
super(invoker); super(invoker);
this.allocateClass = allocateClass; this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor; this.rawConstructor = rawConstructor;
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
}
// for allocation only:
private AllocateObject(Class<C> allocateClass) {
super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
this.allocateClass = allocateClass;
this.rawConstructor = null;
} }
static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) { static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodType rawConType = rawConstructor.type(); MethodType rawConType = rawConstructor.type();
assert(rawConType.parameterType(0) == allocateClass); assert(rawConType.parameterType(0) == allocateClass);
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass); MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
...@@ -129,14 +156,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -129,14 +156,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} else { } else {
MethodHandle invoke = VARARGS_INVOKE; MethodHandle invoke = VARARGS_INVOKE;
MethodType conType = CON_TYPES[nargs]; MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = spreadArguments(rawConstructor, conType, 1); MethodHandle gcon = spreadArgumentsFromPos(rawConstructor, conType, 1);
if (gcon == null) return null; if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon); MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
return collectArguments(galloc, newType, 1, null); return collectArguments(galloc, newType, 1, null);
} }
} }
@Override @Override
public String toString() { String debugString() {
return addTypeString(allocateClass.getSimpleName(), this); return addTypeString(allocateClass.getSimpleName(), this);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -214,9 +241,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -214,9 +241,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// For testing use this: // For testing use this:
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
static final MethodHandle VARARGS_INVOKE; static final MethodHandle VARARGS_INVOKE;
static final MethodHandle ALLOCATE;
static { static {
try { try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true)); VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -278,7 +307,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -278,7 +307,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.base = staticBase(field); this.base = staticBase(field);
} }
@Override @Override
public String toString() { return addTypeString(name, this); } String debugString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); } int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); } void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
...@@ -309,8 +338,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -309,8 +338,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
try { try {
// FIXME: Should not have to create 'f' to get this value. // FIXME: Should not have to create 'f' to get this value.
f = c.getDeclaredField(field.getName()); f = c.getDeclaredField(field.getName());
// Note: Previous line might invalidly throw SecurityException (7042829)
return unsafe.staticFieldBase(f); return unsafe.staticFieldBase(f);
} catch (Exception ee) { } catch (NoSuchFieldException ee) {
throw uncaughtException(ee); throw uncaughtException(ee);
} }
} }
...@@ -747,7 +777,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -747,7 +777,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
.insertParameterTypes(keepPosArgs, arrayType); .insertParameterTypes(keepPosArgs, arrayType);
return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength); return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
} }
static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArgPos) { static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
int arrayLength = target.type().parameterCount() - spreadArgPos; int arrayLength = target.type().parameterCount() - spreadArgPos;
return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength); return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
} }
...@@ -761,9 +791,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -761,9 +791,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// spread the last argument of newType to oldType // spread the last argument of newType to oldType
assert(arrayLength == oldType.parameterCount() - spreadArgPos); assert(arrayLength == oldType.parameterCount() - spreadArgPos);
assert(newType.parameterType(spreadArgPos) == arrayType); assert(newType.parameterType(spreadArgPos) == arrayType);
MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength); return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
if (res == null) throw new IllegalArgumentException("spread on "+target+" with "+arrayType.getSimpleName());
return res;
} }
static MethodHandle collectArguments(MethodHandle target, static MethodHandle collectArguments(MethodHandle target,
...@@ -771,6 +799,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -771,6 +799,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle collector) { MethodHandle collector) {
MethodType type = target.type(); MethodType type = target.type();
Class<?> collectType = collector.type().returnType(); Class<?> collectType = collector.type().returnType();
assert(collectType != void.class); // else use foldArguments
if (collectType != type.parameterType(collectArg)) if (collectType != type.parameterType(collectArg))
target = target.asType(type.changeParameterType(collectArg, collectType)); target = target.asType(type.changeParameterType(collectArg, collectType));
MethodType newType = type MethodType newType = type
...@@ -878,9 +907,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -878,9 +907,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.test = test; this.test = test;
this.target = target; this.target = target;
this.fallback = fallback; this.fallback = fallback;
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
} }
// FIXME: Build the control flow out of foldArguments. // FIXME: Build the control flow out of foldArguments.
static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) { static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodType type = target.type(); MethodType type = target.type();
int nargs = type.parameterCount(); int nargs = type.parameterCount();
if (nargs < INVOKES.length) { if (nargs < INVOKES.length) {
...@@ -897,16 +928,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -897,16 +928,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle invoke = VARARGS_INVOKE; MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1); MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype); assert(invoke.type().dropParameterTypes(0,1) == gtype);
MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0); MethodHandle gtest = spreadArgumentsFromPos(test, gtype.changeReturnType(boolean.class), 0);
MethodHandle gtarget = spreadArguments(target, gtype, 0); MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
MethodHandle gfallback = spreadArguments(fallback, gtype, 0); MethodHandle gfallback = spreadArgumentsFromPos(fallback, gtype, 0);
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback); MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
if (gtest == null || gtarget == null || gfallback == null) return null; if (gtest == null || gtarget == null || gfallback == null) return null;
return collectArguments(gguard, type, 0, null); return collectArguments(gguard, type, 0, null);
} }
} }
@Override @Override
public String toString() { String debugString() {
return addTypeString(target, this); return addTypeString(target, this);
} }
private Object invoke_V(Object... av) throws Throwable { private Object invoke_V(Object... av) throws Throwable {
...@@ -989,10 +1020,49 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -989,10 +1020,49 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
} }
static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
return testResult ? target : fallback;
}
static MethodHandle SELECT_ALTERNATIVE;
static MethodHandle selectAlternative() {
if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
try {
SELECT_ALTERNATIVE
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
return SELECT_ALTERNATIVE;
}
static static
MethodHandle makeGuardWithTest(MethodHandle test, MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target, MethodHandle target,
MethodHandle fallback) { MethodHandle fallback) {
// gwt(arg...)
// [fold]=> continueAfterTest(z=test(arg...), arg...)
// [filter]=> (tf=select(z))(arg...)
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
// [tailcall]=> tf(arg...)
assert(test.type().returnType() == boolean.class);
MethodType foldTargetType = target.type().insertParameterTypes(0, boolean.class);
if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)) {
// working backwards, as usual:
assert(target.type().equals(fallback.type()));
MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
MethodHandle select = selectAlternative();
select = bindArgument(select, 2, fallback);
select = bindArgument(select, 1, target);
// select(z: boolean) => (z ? target : fallback)
MethodHandle filter = filterArgument(tailcall, 0, select);
assert(filter.type().parameterType(0) == boolean.class);
MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
return fold;
}
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
return GuardWithTest.make(test, target, fallback); return GuardWithTest.make(test, target, fallback);
} }
...@@ -1012,7 +1082,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1012,7 +1082,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.catcher = catcher; this.catcher = catcher;
} }
@Override @Override
public String toString() { String debugString() {
return addTypeString(target, this); return addTypeString(target, this);
} }
private Object invoke_V(Object... av) throws Throwable { private Object invoke_V(Object... av) throws Throwable {
...@@ -1144,11 +1214,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1144,11 +1214,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} else { } else {
MethodType gtype = MethodType.genericMethodType(0, true); MethodType gtype = MethodType.genericMethodType(0, true);
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
MethodHandle gtarget = spreadArguments(target, gtype, 0); MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1); catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher); MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null; if (gtarget == null || gcatcher == null || gguard == null) return null;
return collectArguments(gguard, type, 0, null); return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
} }
} }
...@@ -1178,8 +1249,4 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1178,8 +1249,4 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static MethodHandle getBootstrap(Class<?> callerClass) { static MethodHandle getBootstrap(Class<?> callerClass) {
return MethodHandleNatives.getBootstrap(callerClass); return MethodHandleNatives.getBootstrap(callerClass);
} }
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
}
} }
...@@ -35,6 +35,8 @@ package java.lang.invoke; ...@@ -35,6 +35,8 @@ package java.lang.invoke;
private MethodHandleStatics() { } // do not instantiate private MethodHandleStatics() { } // do not instantiate
static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) { /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null) if (type == null)
type = target.type(); type = target.type();
......
...@@ -1065,6 +1065,7 @@ return mh1; ...@@ -1065,6 +1065,7 @@ return mh1;
if (!method.isProtected() || method.isStatic() if (!method.isProtected() || method.isStatic()
|| allowedModes == TRUSTED || allowedModes == TRUSTED
|| method.getDeclaringClass() == lookupClass() || method.getDeclaringClass() == lookupClass()
|| VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass())
|| (ALLOW_NESTMATE_ACCESS && || (ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass()))) VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
return mh; return mh;
...@@ -1377,6 +1378,9 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type) ...@@ -1377,6 +1378,9 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
*/ */
public static public static
MethodHandle convertArguments(MethodHandle target, MethodType newType) { MethodHandle convertArguments(MethodHandle target, MethodType newType) {
if (!target.type().isConvertibleTo(newType)) {
throw new WrongMethodTypeException("cannot convert "+target+" to "+newType);
}
return MethodHandleImpl.convertArguments(target, newType, 1); return MethodHandleImpl.convertArguments(target, newType, 1);
} }
...@@ -1567,7 +1571,7 @@ assert((int)twice.invokeExact(21) == 42); ...@@ -1567,7 +1571,7 @@ assert((int)twice.invokeExact(21) == 42);
int numSpread = (outargs - spreadPos); int numSpread = (outargs - spreadPos);
MethodHandle res = null; MethodHandle res = null;
if (spreadPos >= 0 && numSpread >= 0) { if (spreadPos >= 0 && numSpread >= 0) {
res = MethodHandleImpl.spreadArguments(target, newType, spreadPos); res = MethodHandleImpl.spreadArgumentsFromPos(target, newType, spreadPos);
} }
if (res == null) { if (res == null) {
throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType); throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
...@@ -2135,7 +2139,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 ...@@ -2135,7 +2139,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
int hpc = hargs.size(), tpc = targs.size(); int hpc = hargs.size(), tpc = targs.size();
if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs)) if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
throw misMatchedTypes("target and handler types", ttype, htype); throw misMatchedTypes("target and handler types", ttype, htype);
handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc)); handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
htype = handler.type(); htype = handler.type();
} }
return MethodHandleImpl.makeGuardWithCatch(target, exType, handler); return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
...@@ -2380,9 +2384,4 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 ...@@ -2380,9 +2384,4 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
} }
return null; return null;
} }
/*non-public*/
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
return MethodHandleImpl.asVarargsCollector(target, arrayType);
}
} }
...@@ -163,7 +163,13 @@ class MethodType implements java.io.Serializable { ...@@ -163,7 +163,13 @@ class MethodType implements java.io.Serializable {
public static public static
MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) { MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
boolean notrust = false; // random List impl. could return evil ptypes array boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust); return makeImpl(rtype, listToArray(ptypes), notrust);
}
private static Class<?>[] listToArray(List<Class<?>> ptypes) {
// sanity check the size before the toArray call, since size might be huge
checkSlotCount(ptypes.size());
return ptypes.toArray(NO_PTYPES);
} }
/** /**
...@@ -228,7 +234,7 @@ class MethodType implements java.io.Serializable { ...@@ -228,7 +234,7 @@ class MethodType implements java.io.Serializable {
*/ */
/*trusted*/ static /*trusted*/ static
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) { MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (ptypes == null || ptypes.length == 0) { if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true; ptypes = NO_PTYPES; trusted = true;
} }
MethodType mt1 = new MethodType(rtype, ptypes); MethodType mt1 = new MethodType(rtype, ptypes);
...@@ -372,7 +378,7 @@ class MethodType implements java.io.Serializable { ...@@ -372,7 +378,7 @@ class MethodType implements java.io.Serializable {
* @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
*/ */
public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) { public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES)); return insertParameterTypes(num, listToArray(ptypesToInsert));
} }
/** /**
...@@ -641,7 +647,8 @@ class MethodType implements java.io.Serializable { ...@@ -641,7 +647,8 @@ class MethodType implements java.io.Serializable {
} }
return true; return true;
} }
private static boolean canConvert(Class<?> src, Class<?> dst) { /*non-public*/
static boolean canConvert(Class<?> src, Class<?> dst) {
if (src == dst || dst == void.class) return true; if (src == dst || dst == void.class) return true;
if (src.isPrimitive() && dst.isPrimitive()) { if (src.isPrimitive() && dst.isPrimitive()) {
if (!Wrapper.forPrimitiveType(dst) if (!Wrapper.forPrimitiveType(dst)
...@@ -739,9 +746,14 @@ class MethodType implements java.io.Serializable { ...@@ -739,9 +746,14 @@ class MethodType implements java.io.Serializable {
public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader) public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException throws IllegalArgumentException, TypeNotPresentException
{ {
if (!descriptor.startsWith("(") || // also generates NPE if needed
descriptor.indexOf(')') < 0 ||
descriptor.indexOf('.') >= 0)
throw new IllegalArgumentException("not a method descriptor: "+descriptor);
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader); List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1); Class<?> rtype = types.remove(types.size() - 1);
Class<?>[] ptypes = types.toArray(NO_PTYPES); checkSlotCount(types.size());
Class<?>[] ptypes = listToArray(types);
return makeImpl(rtype, ptypes, true); return makeImpl(rtype, ptypes, true);
} }
......
...@@ -448,6 +448,8 @@ class MethodTypeForm { ...@@ -448,6 +448,8 @@ class MethodTypeForm {
Class<?>[] cs = null; Class<?>[] cs = null;
for (int imax = ts.length, i = 0; i < imax; i++) { for (int imax = ts.length, i = 0; i < imax; i++) {
Class<?> c = canonicalize(ts[i], how); Class<?> c = canonicalize(ts[i], how);
if (c == void.class)
c = null; // a Void parameter was unwrapped to void; ignore
if (c != null) { if (c != null) {
if (cs == null) if (cs == null)
cs = ts.clone(); cs = ts.clone();
......
...@@ -126,7 +126,7 @@ class SpreadGeneric { ...@@ -126,7 +126,7 @@ class SpreadGeneric {
return spreadGen; return spreadGen;
} }
public String toString() { String debugString() {
return getClass().getSimpleName()+targetType+"["+spreadCount+"]"; return getClass().getSimpleName()+targetType+"["+spreadCount+"]";
} }
...@@ -224,7 +224,7 @@ class SpreadGeneric { ...@@ -224,7 +224,7 @@ class SpreadGeneric {
protected final MethodHandle target; // (any**N) => R protected final MethodHandle target; // (any**N) => R
@Override @Override
public String toString() { String debugString() {
return addTypeString(target, this); return addTypeString(target, this);
} }
......
...@@ -258,7 +258,7 @@ class ToGeneric { ...@@ -258,7 +258,7 @@ class ToGeneric {
return toGen; return toGen;
} }
public String toString() { String debugString() {
return "ToGeneric"+entryType return "ToGeneric"+entryType
+(primsAtEndOrder!=null?"[reorder]":""); +(primsAtEndOrder!=null?"[reorder]":"");
} }
...@@ -340,7 +340,7 @@ class ToGeneric { ...@@ -340,7 +340,7 @@ class ToGeneric {
protected final MethodHandle convert; // Object -> R protected final MethodHandle convert; // Object -> R
@Override @Override
public String toString() { String debugString() {
return target == null ? "prototype:"+convert : addTypeString(target, this); return target == null ? "prototype:"+convert : addTypeString(target, this);
} }
......
...@@ -258,7 +258,7 @@ public enum Wrapper { ...@@ -258,7 +258,7 @@ public enum Wrapper {
} }
/** Return the wrapper that wraps values into the given wrapper type. /** Return the wrapper that wraps values into the given wrapper type.
* If it is {@code Object} or an interface, return {@code OBJECT}. * If it is {@code Object}, return {@code OBJECT}.
* Otherwise, it must be a wrapper type. * Otherwise, it must be a wrapper type.
* The type must not be a primitive type. * The type must not be a primitive type.
* @throws IllegalArgumentException for unexpected types * @throws IllegalArgumentException for unexpected types
...@@ -277,8 +277,6 @@ public enum Wrapper { ...@@ -277,8 +277,6 @@ public enum Wrapper {
if (w != null && w.wrapperType == type) { if (w != null && w.wrapperType == type) {
return w; return w;
} }
if (type.isInterface())
return OBJECT;
return null; return null;
} }
......
...@@ -51,10 +51,10 @@ public class Test6991596 { ...@@ -51,10 +51,10 @@ public class Test6991596 {
return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
} }
static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
} }
static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
} }
// test adapter_opt_i2i // test adapter_opt_i2i
......
...@@ -53,9 +53,9 @@ public class InvokeGenericTest { ...@@ -53,9 +53,9 @@ public class InvokeGenericTest {
if (vstr != null) verbosity = Integer.parseInt(vstr); if (vstr != null) verbosity = Integer.parseInt(vstr);
} }
public static void main(String... av) throws Throwable { // public static void main(String... av) throws Throwable {
new InvokeGenericTest().testFirst(); // new InvokeGenericTest().testFirst();
} // }
@Test @Test
public void testFirst() throws Throwable { public void testFirst() throws Throwable {
...@@ -470,8 +470,6 @@ public class InvokeGenericTest { ...@@ -470,8 +470,6 @@ public class InvokeGenericTest {
return allMethodTypes(argc, argc, types); return allMethodTypes(argc, argc, types);
} }
interface RandomInterface { }
MethodHandle toString_MH; MethodHandle toString_MH;
@Test @Test
...@@ -480,33 +478,62 @@ public class InvokeGenericTest { ...@@ -480,33 +478,62 @@ public class InvokeGenericTest {
toString_MH = LOOKUP. toString_MH = LOOKUP.
findVirtual(Object.class, "toString", MethodType.methodType(String.class)); findVirtual(Object.class, "toString", MethodType.methodType(String.class));
Object[] args = { "one", "two" }; Object[] args = { "one", "two" };
for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) { for (MethodType type : allMethodTypes(2, Object.class, String.class, CharSequence.class)) {
testReferenceConversions(type, args); testReferenceConversions(type, args);
} }
} }
public void testReferenceConversions(MethodType type, Object... args) throws Throwable { public void testReferenceConversions(MethodType type, Object... args) throws Throwable {
countTest(); countTest();
if (verbosity > 3) System.out.println("target type: "+type); int nargs = args.length;
List<Object> argList = Arrays.asList(args);
String expectString = argList.toString();
if (verbosity > 3) System.out.println("target type: "+type+expectString);
MethodHandle mh = callable(type.parameterList()); MethodHandle mh = callable(type.parameterList());
MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList()); mh = MethodHandles.filterReturnValue(mh, toString_MH);
mh = MethodHandles.foldArguments(tsdrop, mh);
mh = mh.asType(type); mh = mh.asType(type);
Object res = mh.invoke((String)args[0], (Object)args[1]); Object res = null;
if (nargs == 2) {
res = mh.invoke((Object)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = mh.invoke((Object)args[0], (String)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (String)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (CharSequence)args[1]);
assertEquals(expectString, res);
res = mh.invoke((CharSequence)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (String) mh.invoke((Object)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (String) mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (CharSequence) mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
} else {
assert(false); // write this code
}
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.asList(args).toString(), res);
} }
@Test @Ignore("known failure pending 6939861") @Test
public void testBoxConversions() throws Throwable { public void testBoxConversions() throws Throwable {
startTest("testBoxConversions"); startTest("testBoxConversions");
countTest(); countTest();
Object[] args = { 1, 2 }; Object[] args = { 1, 2 };
MethodHandle mh = callable(Object.class, int.class); MethodHandle mh = callable(Object.class, int.class);
Object res; List resl; Object res; List resl; int resi;
res = resl = (List) mh.invoke((int)args[0], (Object)args[1]); res = resl = (List) mh.invoke((int)args[0], (Object)args[1]);
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.asList(args), res); assertEquals(Arrays.asList(args), res);
mh = MethodHandles.identity(int.class);
mh = MethodHandles.dropArguments(mh, 1, int.class);
res = resi = (int) mh.invoke((Object) args[0], (Object) args[1]);
assertEquals(args[0], res);
res = resi = (int) mh.invoke((int) args[0], (Object) args[1]);
assertEquals(args[0], res);
} }
} }
...@@ -505,8 +505,15 @@ public class MethodHandlesTest { ...@@ -505,8 +505,15 @@ public class MethodHandlesTest {
System.out.print(':'); System.out.print(':');
} }
static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
// rough check of name string // rough check of name string
static void assertNameStringContains(Object x, String s) { static void assertNameStringContains(MethodHandle x, String s) {
if (!DEBUG_METHOD_HANDLE_NAMES) {
// ignore s
assertEquals("MethodHandle"+x.type(), x.toString());
return;
}
if (x.toString().contains(s)) return; if (x.toString().contains(s)) return;
assertEquals(s, x); assertEquals(s, x);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册