// warning ! stolen code ahead ! (http://code.google.com/p/jsr292-cookbook) public static CallSite myBSM(Lookup lookup, String name, MethodType type, Class<?> staticType) throws ReflectiveOperationException { MethodHandle target = lookup.findStatic(staticType, name, type); HashMap<String, HashMap<Object, Object>> cacheTable = cacheTables.get(staticType); String selector = name + type.toMethodDescriptorString(); HashMap<Object, Object> cache = cacheTable.get(selector); if (cache == null) { cache = new HashMap<Object, Object>(); cacheTable.put(selector, cache); } MethodHandle identity = MethodHandles.identity(type.returnType()); identity = identity.asType(identity.type().changeParameterType(0, Object.class)); identity = MethodHandles.dropArguments(identity, 1, type.parameterType(0)); MethodHandle update = UPDATE.bindTo(cache); update = update.asType(type.insertParameterTypes(0, type.returnType())); MethodHandle fallback = MethodHandles.foldArguments(update, target); fallback = MethodHandles.dropArguments(fallback, 0, Object.class); MethodHandle combiner = MethodHandles.guardWithTest(NOT_NULL, identity, fallback); MethodHandle cacheQuerier = MAP_GET.bindTo(cache); cacheQuerier = cacheQuerier.asType(MethodType.methodType(Object.class, type.parameterType(0))); MethodHandle memoize = MethodHandles.foldArguments(combiner, cacheQuerier); return new ConstantCallSite(memoize); }
// Factory methods: static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) { MethodType mtype = member.getMethodOrFieldType(); if (!member.isStatic()) { if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor()) throw new InternalError(member.toString()); mtype = mtype.insertParameterTypes(0, receiver); } if (!member.isField()) { if (refKind == REF_invokeSpecial) { member = member.asSpecial(); LambdaForm lform = preparedLambdaForm(member); return new Special(mtype, lform, member); } else { LambdaForm lform = preparedLambdaForm(member); return new DirectMethodHandle(mtype, lform, member); } } else { LambdaForm lform = preparedFieldLambdaForm(member); if (member.isStatic()) { long offset = MethodHandleNatives.staticFieldOffset(member); Object base = MethodHandleNatives.staticFieldBase(member); return new StaticAccessor(mtype, lform, member, base, offset); } else { long offset = MethodHandleNatives.objectFieldOffset(member); assert (offset == (int) offset); return new Accessor(mtype, lform, member, (int) offset); } } }
/** * Compute and cache information for this adapter, so that it can call out to targets of the * erasure-family of the given erased type. */ /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException { assert (erasedCallerType.equals(erasedCallerType.erase())); this.erasedCallerType = erasedCallerType; this.initialInvoker = makeInitialInvoker(); assert initialInvoker .type() .equals(erasedCallerType.insertParameterTypes(0, MethodType.class, MethodHandle.class)) : initialInvoker.type(); }
public static CallSite ivar(Lookup lookup, String name, MethodType type) throws Throwable { String[] names = name.split(":"); String operation = names[0]; String varName = names[1]; VariableSite site = new VariableSite(type, varName, "noname", 0); MethodHandle handle; handle = lookup.findStatic( Bootstrap.class, operation, type.insertParameterTypes(0, VariableSite.class)); handle = handle.bindTo(site); site.setTarget(handle.asType(site.type())); return site; }
/** * Return the actual type under which this method or constructor must be invoked. For non-static * methods or constructors, this is the type with a leading parameter, a reference to declaring * class. For static methods, it is the same as the declared type. */ public MethodType getInvocationType() { MethodType itype = getMethodType(); if (!isStatic()) itype = itype.insertParameterTypes(0, clazz); return itype; }
private MethodHandle makePostDispatchInvoker() { // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...). MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS); return invokerType.invokers().exactInvoker(); }
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; }