public InvokeSite(MethodType type, String name, CallType callType) { super(type); this.methodName = name; this.callType = callType; Signature startSig; if (callType == CallType.SUPER) { // super calls receive current class argument, so offsets and signature are different startSig = JRubyCallSite.STANDARD_SUPER_SIG; argOffset = 4; } else { startSig = JRubyCallSite.STANDARD_SITE_SIG; argOffset = 3; } int arity; if (type.parameterType(type.parameterCount() - 1) == Block.class) { arity = type.parameterCount() - (argOffset + 1); if (arity == 1 && type.parameterType(argOffset) == IRubyObject[].class) { arity = -1; startSig = startSig.appendArg("args", IRubyObject[].class); } else { for (int i = 0; i < arity; i++) { startSig = startSig.appendArg("arg" + i, IRubyObject.class); } } startSig = startSig.appendArg("block", Block.class); fullSignature = signature = startSig; } else { arity = type.parameterCount() - argOffset; if (arity == 1 && type.parameterType(argOffset) == IRubyObject[].class) { arity = -1; startSig = startSig.appendArg("args", IRubyObject[].class); } else { for (int i = 0; i < arity; i++) { startSig = startSig.appendArg("arg" + i, IRubyObject.class); } } signature = startSig; fullSignature = startSig.appendArg("block", Block.class); } this.arity = arity; this.fallback = prepareBinder().invokeVirtualQuiet(Bootstrap.LOOKUP, "invoke"); }
public CatchExceptionTest( TestCase testCase, final boolean isVararg, final int argsCount, final int catchDrops) { this.testCase = testCase; this.dropped = catchDrops; if (Helper.IS_VERBOSE) { System.out.printf( "CatchException::CatchException(%s, isVararg=%b " + "argsCount=%d catchDrops=%d)%n", testCase, isVararg, argsCount, 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); }
/*non-public*/ boolean isConvertibleTo(MethodType newType) { if (!canConvert(returnType(), newType.returnType())) return false; int argc = parameterCount(); if (argc != newType.parameterCount()) return false; for (int i = 0; i < argc; i++) { if (!canConvert(newType.parameterType(i), parameterType(i))) return false; } return true; }
// Other notes to implementors: // <p> // No stable mapping is promised between the single-method interface and // the implementation class C. Over time, several implementation // classes might be used for the same type. // <p> // If the implementation is able // to prove that a wrapper of the required type // has already been created for a given // method handle, or for another method handle with the // same behavior, the implementation may return that wrapper in place of // a new wrapper. // <p> // This method is designed to apply to common use cases // where a single method handle must interoperate with // an interface that implements a function-like // API. Additional variations, such as single-abstract-method classes with // private constructors, or interfaces with multiple but related // entry points, must be covered by hand-written or automatically // generated adapter classes. // public static <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: " + intfc.getName()); final Method[] methods = getSingleNameMethods(intfc); if (methods == null) throw new IllegalArgumentException("not a single-method interface: " + intfc.getName()); final MethodHandle[] vaTargets = new MethodHandle[methods.length]; for (int i = 0; i < methods.length; i++) { Method sm = methods[i]; MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes()); MethodHandle checkTarget = target.asType(smMT); // make throw WMT checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); } return intfc.cast( Proxy.newProxyInstance( intfc.getClassLoader(), new Class[] {intfc, WrapperInstance.class}, new InvocationHandler() { private Object getArg(String name) { if ((Object) name == "getWrapperInstanceTarget") return target; if ((Object) name == "getWrapperInstanceType") return intfc; throw new AssertionError(); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { for (int i = 0; i < methods.length; i++) { if (method.equals(methods[i])) return vaTargets[i].invokeExact(args); } if (method.getDeclaringClass() == WrapperInstance.class) return getArg(method.getName()); if (isObjectMethod(method)) return callObjectMethod(this, method, args); throw new InternalError("bad proxy method: " + method); } })); }
public MethodType down(MethodType type) { for (int i = 0; i < type.parameterCount(); i++) { type = type.changeParameterType(i, type.parameterArray()[i]); } return type; }
private static LambdaForm makePreparedFieldLambdaForm( byte formOp, boolean isVolatile, int ftypeKind) { boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1); boolean isStatic = (formOp >= AF_GETSTATIC); boolean needsInit = (formOp >= AF_GETSTATIC_INIT); boolean needsCast = (ftypeKind == FT_CHECKED_REF); Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]); Class<?> ft = fw.primitiveType(); assert (ftypeKind(needsCast ? String.class : ft) == ftypeKind); // getObject, putIntVolatile, etc. StringBuilder nameBuilder = new StringBuilder(); if (isGetter) { nameBuilder.append("get"); } else { nameBuilder.append("put"); } nameBuilder.append(fw.primitiveSimpleName()); nameBuilder.setCharAt(3, Character.toUpperCase(nameBuilder.charAt(3))); if (isVolatile) { nameBuilder.append("Volatile"); } MethodType linkerType; if (isGetter) linkerType = MethodType.methodType(ft, Object.class, long.class); else linkerType = MethodType.methodType(void.class, Object.class, long.class, ft); MemberName linker = new MemberName(Unsafe.class, nameBuilder.toString(), linkerType, REF_invokeVirtual); try { linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } // What is the external type of the lambda form? MethodType mtype; if (isGetter) mtype = MethodType.methodType(ft); else mtype = MethodType.methodType(void.class, ft); mtype = mtype.basicType(); // erase short to int, etc. if (!isStatic) mtype = mtype.insertParameterTypes(0, Object.class); final int DMH_THIS = 0; final int ARG_BASE = 1; final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); // if this is for non-static access, the base pointer is stored at this index: final int OBJ_BASE = isStatic ? -1 : ARG_BASE; // if this is for write access, the value to be written is stored at this index: final int SET_VALUE = isGetter ? -1 : ARG_LIMIT - 1; int nameCursor = ARG_LIMIT; final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any final int F_OFFSET = nameCursor++; // Either static offset or field offset. final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1); final int INIT_BAR = (needsInit ? nameCursor++ : -1); final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1); final int LINKER_CALL = nameCursor++; final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1); final int RESULT = nameCursor - 1; // either the call or the cast Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); if (needsInit) names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]); if (needsCast && !isGetter) names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]); Object[] outArgs = new Object[1 + linkerType.parameterCount()]; assert (outArgs.length == (isGetter ? 3 : 4)); outArgs[0] = UNSAFE; if (isStatic) { outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]); outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]); } else { outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]); outArgs[2] = names[F_OFFSET] = new Name(NF_fieldOffset, names[DMH_THIS]); } if (!isGetter) { outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]); } for (Object a : outArgs) assert (a != null); names[LINKER_CALL] = new Name(linker, outArgs); if (needsCast && isGetter) names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]); for (Name n : names) assert (n != null); // add some detail to the lambdaForm debugname, // significant only for debugging if (isStatic) { nameBuilder.append("Static"); } else { nameBuilder.append("Field"); } if (needsCast) nameBuilder.append("Cast"); if (needsInit) nameBuilder.append("Init"); return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT); }
static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) { boolean needsInit = (which == LF_INVSTATIC_INIT); boolean doesAlloc = (which == LF_NEWINVSPECIAL); String linkerName; LambdaForm.Kind kind; switch (which) { case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break; case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break; case LF_INVSTATIC_INIT: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC_INIT; break; case LF_INVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_INVOKE_SPECIAL; break; case LF_INVINTERFACE: linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE; break; case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_NEW_INVOKE_SPECIAL; break; default: throw new InternalError("which=" + which); } MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class); if (doesAlloc) mtypeWithArg = mtypeWithArg .insertParameterTypes(0, Object.class) // insert newly allocated obj .changeReturnType(void.class); // <init> returns void MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic); try { linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } final int DMH_THIS = 0; final int ARG_BASE = 1; final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); int nameCursor = ARG_LIMIT; final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1); final int GET_MEMBER = nameCursor++; final int LINKER_CALL = nameCursor++; Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); assert (names.length == nameCursor); if (doesAlloc) { // names = { argx,y,z,... new C, init method } names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]); names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]); } else if (needsInit) { names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]); } else { names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]); } assert (findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]); Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER + 1, Object[].class); assert (outArgs[outArgs.length - 1] == names[GET_MEMBER]); // look, shifted args! int result = LAST_RESULT; if (doesAlloc) { assert (outArgs[outArgs.length - 2] == names[NEW_OBJ]); // got to move this one System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length - 2); outArgs[0] = names[NEW_OBJ]; result = NEW_OBJ; } names[LINKER_CALL] = new Name(linker, outArgs); String lambdaName = kind.defaultLambdaName + "_" + shortenSignature(basicTypeSignature(mtype)); LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result, kind); // This is a tricky bit of code. Don't send it through the LF interpreter. lform.compileToBytecode(); return lform; }