下面列出了java.lang.invoke.MethodHandles#guardWithTest ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static MethodHandle buildSetter(Class<?> arrayClass) {
MethodHandle set = MethodHandles.arrayElementSetter(arrayClass);
MethodHandle fallback = MethodHandles.explicitCastArguments(set, set.type().changeParameterType(0, Object.class));
fallback = MethodHandles.dropArguments(fallback, 3, int.class);
MethodType reorderType = fallback.type().
insertParameterTypes(0, int.class).
dropParameterTypes(4, 5);
fallback = MethodHandles.permuteArguments(fallback, reorderType, 1, 0, 3, 0);
fallback = MethodHandles.foldArguments(fallback, normalizeIndex);
fallback = MethodHandles.explicitCastArguments(fallback, set.type());
MethodHandle guard = MethodHandles.dropArguments(notNegative, 0, arrayClass);
MethodHandle handle = MethodHandles.guardWithTest(guard, set, fallback);
return handle;
}
private static MethodHandle setCallSiteTarget(MutableCallSite callsite, MethodHandle target, MethodHandle test,
MethodHandle generic) {
MethodHandle callSiteTarget;
if (target != null) {
target = target.asType(callsite.type());
if (test != null) {
MethodHandle fallback = createFallback(callsite, generic);
callSiteTarget = MethodHandles.guardWithTest(test, target, fallback);
} else {
callSiteTarget = target;
}
} else {
callSiteTarget = target = generic;
}
callsite.setTarget(callSiteTarget);
return target;
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @param catchFallback the fallback method in case the exception handler triggers
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
final MethodHandle guarded =
guard == null ?
invocation :
MethodHandles.guardWithTest(
guard,
invocation,
guardFallback);
final MethodHandle catchGuarded =
exception == null ?
guarded :
MH.catchException(
guarded,
exception,
MethodHandles.dropArguments(
catchFallback,
0,
exception));
if (switchPoints == null) {
return catchGuarded;
}
MethodHandle spGuarded = catchGuarded;
for (final SwitchPoint sp : switchPoints) {
spGuarded = sp.guardWithTest(spGuarded, switchpointFallback);
}
return spGuarded;
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @param catchFallback the fallback method in case the exception handler triggers
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
final MethodHandle guarded =
guard == null ?
invocation :
MethodHandles.guardWithTest(
guard,
invocation,
guardFallback);
final MethodHandle catchGuarded =
exception == null ?
guarded :
MH.catchException(
guarded,
exception,
MethodHandles.dropArguments(
catchFallback,
0,
exception));
if (switchPoints == null) {
return catchGuarded;
}
MethodHandle spGuarded = catchGuarded;
for (final SwitchPoint sp : switchPoints) {
spGuarded = sp.guardWithTest(spGuarded, switchpointFallback);
}
return spGuarded;
}
private MethodHandle getGuardedMethod(CacheEntry entry,
MethodHandle fallback) {
MethodHandle test = entry.receiverClass == null ? NIL_TEST_METHOD_HANDLE
: MethodHandles.insertArguments(
TYPE_TEST_METHOD_HANDLE, 1, entry.receiverClass);
Class[] tail = ArrayExtensions.tail(type.parameterArray());
test = MethodHandles.dropArguments(test, 1, tail);
test = test.asType(MethodType.methodType(Boolean.TYPE,
type.parameterArray()));
MethodHandle guard1 = MethodHandles.guardWithTest(test,
entry.methodHandle, fallback);
return guard1;
}
/**
* Composes the invocation, guard, switch points, and the exception into a
* composite method handle that knows how to fall back when the guard fails
* or the invocation is invalidated.
* @param switchpointFallback the fallback method handle in case a switch
* point is invalidated.
* @param guardFallback the fallback method handle in case guard returns
* false.
* @param catchFallback the fallback method in case the exception handler
* triggers.
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
final MethodHandle guarded =
guard == null ?
invocation :
MethodHandles.guardWithTest(
guard,
invocation,
guardFallback);
final MethodHandle catchGuarded =
exception == null ?
guarded :
MethodHandles.catchException(
guarded,
exception,
MethodHandles.dropArguments(
catchFallback,
0,
exception));
if (switchPoints == null) {
return catchGuarded;
}
MethodHandle spGuarded = catchGuarded;
for (final SwitchPoint sp : switchPoints) {
spGuarded = sp.guardWithTest(spGuarded, switchpointFallback);
}
return spGuarded;
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
return debug(mh, "guardWithTest", test, target, fallback);
}
MethodHandle guardWithTest(final MethodHandle test) {
return MethodHandles.guardWithTest(test, method1, method2);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
return debug(mh, "guardWithTest", test, target, fallback);
}
MethodHandle guardWithTest(final MethodHandle test) {
return MethodHandles.guardWithTest(test, method1, method2);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
return debug(mh, "guardWithTest", test, target, fallback);
}
MethodHandle guardWithTest(final MethodHandle test) {
return MethodHandles.guardWithTest(test, method1, method2);
}
/**
* Given a method handle and a call site type, adapts the method handle to the call site type. Performs type
* conversions as needed using the specified linker services, and in case that the method handle is a vararg
* collector, matches it to the arity of the call site.
* @param target the method handle to adapt
* @param callSiteType the type of the call site
* @param linkerServices the linker services used for type conversions
* @return the adapted method handle.
*/
static MethodHandle getInvocation(MethodHandle target, MethodType callSiteType, LinkerServices linkerServices) {
final MethodType methodType = target.type();
final int paramsLen = methodType.parameterCount();
final boolean varArgs = target.isVarargsCollector();
final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
final int argsLen = callSiteType.parameterCount();
if(argsLen < fixParamsLen) {
// Less actual arguments than number of fixed declared arguments; can't invoke.
return null;
}
// Method handle has the same number of fixed arguments as the call site type
if(argsLen == fixParamsLen) {
// Method handle that matches the number of actual arguments as the number of fixed arguments
final MethodHandle matchedMethod;
if(varArgs) {
// If vararg, add a zero-length array of the expected type as the last argument to signify no variable
// arguments.
matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
methodType.parameterType(fixParamsLen).getComponentType(), 0));
} else {
// Otherwise, just use the method
matchedMethod = fixTarget;
}
return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
}
// What's below only works for varargs
if(!varArgs) {
return null;
}
final Class<?> varArgType = methodType.parameterType(fixParamsLen);
// Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
// must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
if(argsLen == paramsLen) {
final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
if(varArgType.isAssignableFrom(callSiteLastArgType)) {
// Call site signature guarantees we'll always be passed a single compatible array; just link directly
// to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
callSiteLastArgType);
}
if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
// Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
// link immediately to a vararg-packing method handle.
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
}
// Call site signature makes no guarantees that the single argument in the vararg position will be
// compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
// method when it is not.
return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
createConvertingInvocation(fixTarget, linkerServices, callSiteType),
createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
}
// Remaining case: more than one vararg.
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
return MethodHandles.guardWithTest(test, target, fallback);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
return debug(mh, "guardWithTest", test, target, fallback);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
return MethodHandles.guardWithTest(test, target, fallback);
}
MethodHandle guardWithTest(final MethodHandle test) {
return MethodHandles.guardWithTest(test, method1, method2);
}
@Override
public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
return MethodHandles.guardWithTest(test, target, fallback);
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @return a composite method handle.
*/
public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) {
final MethodHandle guarded =
guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback);
return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback);
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @return a composite method handle.
*/
public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) {
final MethodHandle guarded =
guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback);
return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback);
}