下面列出了java.lang.invoke.MethodType#parameterType ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Return a fast linked array getter, or null if we have to dispatch to super class
* @param desc descriptor
* @param request link request
* @return invocation or null if needs to be sent to slow relink
*/
@Override
public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType callType = desc.getMethodType();
final Class<?> indexType = callType.parameterType(1);
final Class<?> returnType = callType.returnType();
if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) {
final Object[] args = request.getArguments();
final int index = (int)args[args.length - 1];
if (has(index)) {
final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
MethodHandle getElement = getElementGetter(returnType, programPoint);
if (getElement != null) {
getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz)));
final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class);
}
}
}
return null;
}
public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount,
final int catchDrops) {
this.testCase = testCase;
this.dropped = catchDrops;
MethodHandle thrower = testCase.thrower;
int throwerLen = thrower.type().parameterCount();
List<Class<?>> classes;
int extra = Math.max(0, argsCount - throwerLen);
classes = getThrowerParams(isVararg, extra);
this.argsCount = throwerLen + classes.size();
thrower = Helper.addTrailingArgs(thrower, this.argsCount, classes);
if (isVararg && argsCount > throwerLen) {
MethodType mt = thrower.type();
Class<?> lastParam = mt.parameterType(mt.parameterCount() - 1);
thrower = thrower.asVarargsCollector(lastParam);
}
this.thrower = thrower;
this.dropped = Math.min(this.argsCount, catchDrops);
catcher = testCase.getCatcher(getCatcherParams());
nargs = Math.max(2, this.argsCount);
}
/**
* Find the appropriate GETINDEX method for an invoke dynamic call.
*
* @param desc the call site descriptor
* @param request the link request
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType callType = desc.getMethodType();
final Class<?> returnType = callType.returnType();
final Class<?> returnClass = returnType.isPrimitive() ? returnType : Object.class;
final Class<?> keyClass = callType.parameterType(1);
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
final String name;
if (returnClass.isPrimitive()) {
//turn e.g. get with a double into getDouble
final String returnTypeName = returnClass.getName();
name = "get" + Character.toUpperCase(returnTypeName.charAt(0)) + returnTypeName.substring(1, returnTypeName.length());
} else {
name = "get";
}
final MethodHandle mh = findGetIndexMethodHandle(returnClass, name, keyClass, desc);
return new GuardedInvocation(mh, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
}
private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) {
assertParameterCount(callSiteDescriptor, 1);
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
// If declared type of receiver at the call site is already an array, collection, or map, bind without guard.
// Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance
// they're dealing with an array, collection, or map, but hey...
if(declaredType.isArray()) {
return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType));
} else if(Collection.class.isAssignableFrom(declaredType)) {
return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType));
} else if(Map.class.isAssignableFrom(declaredType)) {
return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType));
}
// Otherwise, create a binding based on the actual type of the argument with an appropriate guard.
if(clazz.isArray()) {
return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType), Guards.isArray(0,
callSiteType), ValidationType.IS_ARRAY);
} if(Collection.class.isAssignableFrom(clazz)) {
return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType(
COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF);
} if(Map.class.isAssignableFrom(clazz)) {
return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD,
callSiteType), Map.class, ValidationType.INSTANCE_OF);
}
// Can't retrieve length for objects that are neither arrays, nor collections, nor maps.
return null;
}
/**
* Test of parameterType method, of class MethodType.
*/
@Test
public void testParameterType() {
System.out.println("parameterType");
for (int num = 0; num < ptypes.length; num++) {
MethodType instance = mt_viS;
Class<?> expResult = ptypes[num];
Class<?> result = instance.parameterType(num);
assertSame(expResult, result);
}
}
private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) {
final MethodType targetType = new FunctionSignature(fn).getMethodType();
MethodHandle target =
MH.findStatic(
LOOKUP,
fn.getCompileUnit().getCode(),
fn.getName(),
targetType);
/*
* For any integer argument. a double that is representable as an integer is OK.
* otherwise the guard would have failed. in that case introduce a filter that
* casts the double to an integer, which we know will preserve all precision.
*/
for (int i = 0; i < targetType.parameterCount(); i++) {
if (targetType.parameterType(i) == int.class) {
//representable as int
target = MH.filterArguments(target, i, ENSURE_INT);
}
}
MethodHandle mh = target;
if (guard != null) {
mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
}
final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh);
code.add(cf);
return cf.getInvoker();
}
/**
* Creates a guard method handle with arguments of a specified type, but with boolean return value. When invoked, it
* returns true if the first argument is of the specified class (exactly of it, not a subclass). The rest of the
* arguments will be ignored.
*
* @param clazz the class of the first argument to test for
* @param type the method type
* @return a method handle testing whether its first argument is of the specified class.
*/
@SuppressWarnings("boxing")
public static MethodHandle isOfClass(Class<?> clazz, MethodType type) {
final Class<?> declaredType = type.parameterType(0);
if(clazz == declaredType) {
LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(clazz)) {
LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type });
return constantFalse(type);
}
return getClassBoundArgumentTest(IS_OF_CLASS, clazz, 0, type);
}
/**
* Heuristic to figure out if the method handle has a callee argument. If it's type is either
* {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
* a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
* assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
* they also always receive a callee).
*
* @param mh the examined method handle
*
* @return true if the method handle expects a callee, false otherwise
*/
protected static boolean needsCallee(final MethodHandle mh) {
final MethodType type = mh.type();
final int length = type.parameterCount();
if (length == 0) {
return false;
}
if (type.parameterType(0) == boolean.class) {
return length > 1 && type.parameterType(1) == ScriptFunction.class;
}
return type.parameterType(0) == ScriptFunction.class;
}
/**
* Creates a method handle that returns true if the argument in the specified position is a Java array.
*
* @param pos the position in the argument lit
* @param type the method type of the handle
* @return a method handle that returns true if the argument in the specified position is a Java array; the rest of
* the arguments are ignored.
*/
@SuppressWarnings("boxing")
public static MethodHandle isArray(final int pos, final MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(Object[].class)) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return asType(IS_ARRAY, pos, type);
}
private static MethodType widen(final MethodType cftype) {
final Class<?>[] paramTypes = new Class<?>[cftype.parameterCount()];
for (int i = 0; i < cftype.parameterCount(); i++) {
paramTypes[i] = cftype.parameterType(i).isPrimitive() ? cftype.parameterType(i) : Object.class;
}
return MH.type(cftype.returnType(), paramTypes);
}
/**
* Creates a method handle that returns true if the argument in the specified position is a Java array.
*
* @param pos the position in the argument lit
* @param type the method type of the handle
* @return a method handle that returns true if the argument in the specified position is a Java array; the rest of
* the arguments are ignored.
*/
@SuppressWarnings("boxing")
public static MethodHandle isArray(final int pos, final MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(Object[].class)) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return asType(IS_ARRAY, pos, type);
}
/**
* Test of parameterType method, of class MethodType.
*/
@Test
public void testParameterType() {
System.out.println("parameterType");
for (int num = 0; num < ptypes.length; num++) {
MethodType instance = mt_viS;
Class<?> expResult = ptypes[num];
Class<?> result = instance.parameterType(num);
assertSame(expResult, result);
}
}
/**
* Test of parameterType method, of class MethodType.
*/
@Test
public void testParameterType() {
System.out.println("parameterType");
for (int num = 0; num < ptypes.length; num++) {
MethodType instance = mt_viS;
Class<?> expResult = ptypes[num];
Class<?> result = instance.parameterType(num);
assertSame(expResult, result);
}
}
/**
* Creates a method handle that returns true if the argument in the specified position is a Java array.
*
* @param pos the position in the argument lit
* @param type the method type of the handle
* @return a method handle that returns true if the argument in the specified position is a Java array; the rest of
* the arguments are ignored.
*/
@SuppressWarnings("boxing")
public static MethodHandle isArray(int pos, MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(Object[].class)) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type });
return constantFalse(type);
}
return asType(IS_ARRAY, pos, type);
}
/**
* Creates a method handle that returns true if the argument in the specified position is a Java array.
*
* @param pos the position in the argument lit
* @param type the method type of the handle
* @return a method handle that returns true if the argument in the specified position is a Java array; the rest of
* the arguments are ignored.
*/
@SuppressWarnings("boxing")
public static MethodHandle isArray(final int pos, final MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(Object[].class)) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return asType(IS_ARRAY, pos, type);
}
private static Class<?> getParameterClass(final MethodType t, final int l, final int i, final boolean varArgs) {
return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i);
}
private GuardedInvocationComponent getElementSetter(CallSiteDescriptor callSiteDescriptor,
LinkerServices linkerServices, List<String> operations) throws Exception {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent gic;
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
// dealing with an array, or a list or map, but hey...
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
final boolean isMap;
if(declaredType.isArray()) {
gic = new GuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType));
isMap = false;
} else if(List.class.isAssignableFrom(declaredType)) {
gic = new GuardedInvocationComponent(SET_LIST_ELEMENT);
isMap = false;
} else if(Map.class.isAssignableFrom(declaredType)) {
gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT);
isMap = true;
} else if(clazz.isArray()) {
gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementSetter(clazz), callSiteType);
isMap = false;
} else if(List.class.isAssignableFrom(clazz)) {
gic = new GuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class,
ValidationType.INSTANCE_OF);
isMap = false;
} else if(Map.class.isAssignableFrom(clazz)) {
gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class,
ValidationType.INSTANCE_OF);
isMap = true;
} else {
// Can't set elements for objects that are neither arrays, nor list, nor maps.
gic = null;
isMap = false;
}
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
// as maps will always succeed in setting the element and will never need to fall back to the next component
// operation.
final GuardedInvocationComponent nextComponent = isMap ? null : getGuardedInvocationComponent(
callSiteDescriptor, linkerServices, operations);
if(gic == null) {
return nextComponent;
}
// We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo"
final String fixedKey = getFixedKey(callSiteDescriptor);
// Convert the key to a number if we're working with a list or array
final Object typedFixedKey;
if(!isMap && fixedKey != null) {
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
if(typedFixedKey == null) {
// key is not numeric, it can never succeed
return nextComponent;
}
} else {
typedFixedKey = fixedKey;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
final MethodHandle invocation = gi.getInvocation();
if(nextComponent == null) {
return gic.replaceInvocation(binder.bind(invocation));
}
final MethodHandle checkGuard = convertArgToInt(invocation == SET_LIST_ELEMENT ? RANGE_CHECK_LIST :
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard),
binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(),
gic.getValidatorClass(), gic.getValidationType());
}
private static Class<?> getParameterClass(final MethodType t, final int l, final int i, final boolean varArgs) {
return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i);
}
private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType,
SingleDynamicMethod m) {
final MethodType methodType = m.getMethodType();
final boolean varArgs = m.isVarArgs();
final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
final int callSiteArgLen = callSiteType.parameterCount();
// Arity checks
if(varArgs) {
if(callSiteArgLen < fixedArgLen) {
return false;
}
} else if(callSiteArgLen != fixedArgLen) {
return false;
}
// Fixed arguments type checks, starting from 1, as receiver type doesn't participate
for(int i = 1; i < fixedArgLen; ++i) {
if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) {
return false;
}
}
if(!varArgs) {
// Not vararg; both arity and types matched.
return true;
}
final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen);
final Class<?> varArgType = varArgArrayType.getComponentType();
if(fixedArgLen == callSiteArgLen - 1) {
// Exactly one vararg; check both array type matching and array component type matching.
final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen);
return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType)
|| isApplicableDynamically(linkerServices, callSiteArgType, varArgType);
}
// Either zero, or more than one vararg; check if all actual vararg types match the vararg array component type.
for(int i = fixedArgLen; i < callSiteArgLen; ++i) {
if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) {
return false;
}
}
return true;
}
private static Class<?> getParameterClass(final MethodType t, final int l, final int i, final boolean varArgs) {
return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i);
}