jaroslav@1646: /* jaroslav@1646: * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. jaroslav@1646: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@1646: * jaroslav@1646: * This code is free software; you can redistribute it and/or modify it jaroslav@1646: * under the terms of the GNU General Public License version 2 only, as jaroslav@1646: * published by the Free Software Foundation. Oracle designates this jaroslav@1646: * particular file as subject to the "Classpath" exception as provided jaroslav@1646: * by Oracle in the LICENSE file that accompanied this code. jaroslav@1646: * jaroslav@1646: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@1646: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@1646: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@1646: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@1646: * accompanied this code). jaroslav@1646: * jaroslav@1646: * You should have received a copy of the GNU General Public License version jaroslav@1646: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@1646: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@1646: * jaroslav@1646: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@1646: * or visit www.oracle.com if you need additional information or have any jaroslav@1646: * questions. jaroslav@1646: */ jaroslav@1646: jaroslav@1646: package java.lang.invoke; jaroslav@1646: jaroslav@1646: import java.util.Arrays; jaroslav@1646: import sun.invoke.empty.Empty; jaroslav@1646: import static java.lang.invoke.MethodHandleStatics.*; jaroslav@1646: import static java.lang.invoke.MethodHandleNatives.Constants.*; jaroslav@1646: import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; jaroslav@1646: import static java.lang.invoke.LambdaForm.*; jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Construction and caching of often-used invokers. jaroslav@1646: * @author jrose jaroslav@1646: */ jaroslav@1646: class Invokers { jaroslav@1646: // exact type (sans leading taget MH) for the outgoing call jaroslav@1646: private final MethodType targetType; jaroslav@1646: jaroslav@1646: // FIXME: Get rid of the invokers that are not useful. jaroslav@1646: jaroslav@1646: // exact invoker for the outgoing call jaroslav@1646: private /*lazy*/ MethodHandle exactInvoker; jaroslav@1646: private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) jaroslav@1646: jaroslav@1646: // erased (partially untyped but with primitives) invoker for the outgoing call jaroslav@1646: // FIXME: get rid of jaroslav@1646: private /*lazy*/ MethodHandle erasedInvoker; jaroslav@1646: // FIXME: get rid of jaroslav@1646: /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric jaroslav@1646: jaroslav@1646: // general invoker for the outgoing call jaroslav@1646: private /*lazy*/ MethodHandle generalInvoker; jaroslav@1646: jaroslav@1646: // general invoker for the outgoing call, uses varargs jaroslav@1646: private /*lazy*/ MethodHandle varargsInvoker; jaroslav@1646: jaroslav@1646: // general invoker for the outgoing call; accepts a trailing Object[] jaroslav@1646: private final /*lazy*/ MethodHandle[] spreadInvokers; jaroslav@1646: jaroslav@1646: // invoker for an unbound callsite jaroslav@1646: private /*lazy*/ MethodHandle uninitializedCallSite; jaroslav@1646: jaroslav@1646: /** Compute and cache information common to all collecting adapters jaroslav@1646: * that implement members of the erasure-family of the given erased type. jaroslav@1646: */ jaroslav@1646: /*non-public*/ Invokers(MethodType targetType) { jaroslav@1646: this.targetType = targetType; jaroslav@1646: this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1]; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle exactInvoker() { jaroslav@1646: MethodHandle invoker = exactInvoker; jaroslav@1646: if (invoker != null) return invoker; jaroslav@1646: invoker = makeExactOrGeneralInvoker(true); jaroslav@1646: exactInvoker = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle generalInvoker() { jaroslav@1646: MethodHandle invoker = generalInvoker; jaroslav@1646: if (invoker != null) return invoker; jaroslav@1646: invoker = makeExactOrGeneralInvoker(false); jaroslav@1646: generalInvoker = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { jaroslav@1646: MethodType mtype = targetType; jaroslav@1646: MethodType invokerType = mtype.invokerType(); jaroslav@1646: int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER); jaroslav@1646: LambdaForm lform = invokeHandleForm(mtype, false, which); jaroslav@1646: MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); jaroslav@1646: String whichName = (isExact ? "invokeExact" : "invoke"); jaroslav@1646: invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype)); jaroslav@1646: assert(checkInvoker(invoker)); jaroslav@1646: maybeCompileToBytecode(invoker); jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */ jaroslav@1646: private void maybeCompileToBytecode(MethodHandle invoker) { jaroslav@1646: final int EAGER_COMPILE_ARITY_LIMIT = 10; jaroslav@1646: if (targetType == targetType.erase() && jaroslav@1646: targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) { jaroslav@1646: invoker.form.compileToBytecode(); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle basicInvoker() { jaroslav@1646: MethodHandle invoker = basicInvoker; jaroslav@1646: if (invoker != null) return invoker; jaroslav@1646: MethodType basicType = targetType.basicType(); jaroslav@1646: if (basicType != targetType) { jaroslav@1646: // double cache; not used significantly jaroslav@1646: return basicInvoker = basicType.invokers().basicInvoker(); jaroslav@1646: } jaroslav@1646: MemberName method = invokeBasicMethod(basicType); jaroslav@1646: invoker = DirectMethodHandle.make(method); jaroslav@1646: assert(checkInvoker(invoker)); jaroslav@1646: basicInvoker = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: // This next one is called from LambdaForm.NamedFunction.. jaroslav@1646: /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { jaroslav@1646: assert(basicType == basicType.basicType()); jaroslav@1646: try { jaroslav@1646: //Lookup.findVirtual(MethodHandle.class, name, type); jaroslav@1646: return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); jaroslav@1646: } catch (ReflectiveOperationException ex) { jaroslav@1646: throw newInternalError("JVM cannot find invoker for "+basicType, ex); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: private boolean checkInvoker(MethodHandle invoker) { jaroslav@1646: assert(targetType.invokerType().equals(invoker.type())) jaroslav@1646: : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker); jaroslav@1646: assert(invoker.internalMemberName() == null || jaroslav@1646: invoker.internalMemberName().getMethodType().equals(targetType)); jaroslav@1646: assert(!invoker.isVarargsCollector()); jaroslav@1646: return true; jaroslav@1646: } jaroslav@1646: jaroslav@1646: // FIXME: get rid of jaroslav@1646: /*non-public*/ MethodHandle erasedInvoker() { jaroslav@1646: MethodHandle xinvoker = exactInvoker(); jaroslav@1646: MethodHandle invoker = erasedInvoker; jaroslav@1646: if (invoker != null) return invoker; jaroslav@1646: MethodType erasedType = targetType.erase(); jaroslav@1646: invoker = xinvoker.asType(erasedType.invokerType()); jaroslav@1646: erasedInvoker = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { jaroslav@1646: MethodHandle vaInvoker = spreadInvokers[leadingArgCount]; jaroslav@1646: if (vaInvoker != null) return vaInvoker; jaroslav@1646: int spreadArgCount = targetType.parameterCount() - leadingArgCount; jaroslav@1646: MethodType spreadInvokerType = targetType jaroslav@1646: .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class); jaroslav@1646: if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { jaroslav@1646: // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a) jaroslav@1646: // where ginvoker.invoke(mh, a*) => mh.invoke(a*). jaroslav@1646: MethodHandle genInvoker = generalInvoker(); jaroslav@1646: vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount); jaroslav@1646: } else { jaroslav@1646: // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]). jaroslav@1646: // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a) jaroslav@1646: // where filter(mh) == mh.asSpreader(Object[], spreadArgCount) jaroslav@1646: MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType); jaroslav@1646: MethodHandle makeSpreader; jaroslav@1646: try { jaroslav@1646: makeSpreader = IMPL_LOOKUP jaroslav@1646: .findVirtual(MethodHandle.class, "asSpreader", jaroslav@1646: MethodType.methodType(MethodHandle.class, Class.class, int.class)); jaroslav@1646: } catch (ReflectiveOperationException ex) { jaroslav@1646: throw newInternalError(ex); jaroslav@1646: } jaroslav@1646: makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount); jaroslav@1646: vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); jaroslav@1646: } jaroslav@1646: assert(vaInvoker.type().equals(spreadInvokerType.invokerType())); jaroslav@1646: maybeCompileToBytecode(vaInvoker); jaroslav@1646: spreadInvokers[leadingArgCount] = vaInvoker; jaroslav@1646: return vaInvoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle varargsInvoker() { jaroslav@1646: MethodHandle vaInvoker = varargsInvoker; jaroslav@1646: if (vaInvoker != null) return vaInvoker; jaroslav@1646: vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType()); jaroslav@1646: varargsInvoker = vaInvoker; jaroslav@1646: return vaInvoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private static MethodHandle THROW_UCS = null; jaroslav@1646: jaroslav@1646: /*non-public*/ MethodHandle uninitializedCallSite() { jaroslav@1646: MethodHandle invoker = uninitializedCallSite; jaroslav@1646: if (invoker != null) return invoker; jaroslav@1646: if (targetType.parameterCount() > 0) { jaroslav@1646: MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount()); jaroslav@1646: Invokers invokers0 = type0.invokers(); jaroslav@1646: invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(), jaroslav@1646: 0, targetType.parameterList()); jaroslav@1646: assert(invoker.type().equals(targetType)); jaroslav@1646: uninitializedCallSite = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: invoker = THROW_UCS; jaroslav@1646: if (invoker == null) { jaroslav@1646: try { jaroslav@1646: THROW_UCS = invoker = IMPL_LOOKUP jaroslav@1646: .findStatic(CallSite.class, "uninitializedCallSite", jaroslav@1646: MethodType.methodType(Empty.class)); jaroslav@1646: } catch (ReflectiveOperationException ex) { jaroslav@1646: throw newInternalError(ex); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType())); jaroslav@1646: invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount()); jaroslav@1646: assert(invoker.type().equals(targetType)); jaroslav@1646: uninitializedCallSite = invoker; jaroslav@1646: return invoker; jaroslav@1646: } jaroslav@1646: jaroslav@1646: public String toString() { jaroslav@1646: return "Invokers"+targetType; jaroslav@1646: } jaroslav@1646: jaroslav@1646: static MemberName methodHandleInvokeLinkerMethod(String name, jaroslav@1646: MethodType mtype, jaroslav@1646: Object[] appendixResult) { jaroslav@1646: int which; jaroslav@1646: switch (name) { jaroslav@1646: case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break; jaroslav@1646: case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break; jaroslav@1646: default: throw new InternalError("not invoker: "+name); jaroslav@1646: } jaroslav@1646: LambdaForm lform; jaroslav@1646: if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { jaroslav@1646: lform = invokeHandleForm(mtype, false, which); jaroslav@1646: appendixResult[0] = mtype; jaroslav@1646: } else { jaroslav@1646: lform = invokeHandleForm(mtype, true, which); jaroslav@1646: } jaroslav@1646: return lform.vmentry; jaroslav@1646: } jaroslav@1646: jaroslav@1646: // argument count to account for trailing "appendix value" (typically the mtype) jaroslav@1646: private static final int MH_LINKER_ARG_APPENDED = 1; jaroslav@1646: jaroslav@1646: /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker. jaroslav@1646: * If !customized, caller is responsible for supplying, during adapter execution, jaroslav@1646: * a copy of the exact mtype. This is because the adapter might be generalized to jaroslav@1646: * a basic type. jaroslav@1646: * @param mtype the caller's method type (either basic or full-custom) jaroslav@1646: * @param customized whether to use a trailing appendix argument (to carry the mtype) jaroslav@1646: * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker"); jaroslav@1646: * 0x02 whether it is for invokeExact or generic invoke jaroslav@1646: */ jaroslav@1646: private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) { jaroslav@1646: boolean isCached; jaroslav@1646: if (!customized) { jaroslav@1646: mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. jaroslav@1646: isCached = true; jaroslav@1646: } else { jaroslav@1646: isCached = false; // maybe cache if mtype == mtype.basicType() jaroslav@1646: } jaroslav@1646: boolean isLinker, isGeneric; jaroslav@1646: String debugName; jaroslav@1646: switch (which) { jaroslav@1646: case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break; jaroslav@1646: case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break; jaroslav@1646: case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break; jaroslav@1646: case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break; jaroslav@1646: default: throw new InternalError(); jaroslav@1646: } jaroslav@1646: LambdaForm lform; jaroslav@1646: if (isCached) { jaroslav@1646: lform = mtype.form().cachedLambdaForm(which); jaroslav@1646: if (lform != null) return lform; jaroslav@1646: } jaroslav@1646: // exactInvokerForm (Object,Object)Object jaroslav@1646: // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial jaroslav@1646: final int THIS_MH = 0; jaroslav@1646: final int CALL_MH = THIS_MH + (isLinker ? 0 : 1); jaroslav@1646: final int ARG_BASE = CALL_MH + 1; jaroslav@1646: final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); jaroslav@1646: final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0); jaroslav@1646: int nameCursor = OUTARG_LIMIT; jaroslav@1646: final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument jaroslav@1646: final int CHECK_TYPE = nameCursor++; jaroslav@1646: final int LINKER_CALL = nameCursor++; jaroslav@1646: MethodType invokerFormType = mtype.invokerType(); jaroslav@1646: if (isLinker) { jaroslav@1646: if (!customized) jaroslav@1646: invokerFormType = invokerFormType.appendParameterTypes(MemberName.class); jaroslav@1646: } else { jaroslav@1646: invokerFormType = invokerFormType.invokerType(); jaroslav@1646: } jaroslav@1646: Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); jaroslav@1646: assert(names.length == nameCursor) jaroslav@1646: : Arrays.asList(mtype, customized, which, nameCursor, names.length); jaroslav@1646: if (MTYPE_ARG >= INARG_LIMIT) { jaroslav@1646: assert(names[MTYPE_ARG] == null); jaroslav@1646: NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); jaroslav@1646: names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); jaroslav@1646: // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) jaroslav@1646: } jaroslav@1646: jaroslav@1646: // Make the final call. If isGeneric, then prepend the result of type checking. jaroslav@1646: MethodType outCallType = mtype.basicType(); jaroslav@1646: Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); jaroslav@1646: Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]); jaroslav@1646: if (!isGeneric) { jaroslav@1646: names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg); jaroslav@1646: // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*) jaroslav@1646: } else { jaroslav@1646: names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg); jaroslav@1646: // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) jaroslav@1646: outArgs[0] = names[CHECK_TYPE]; jaroslav@1646: } jaroslav@1646: names[LINKER_CALL] = new Name(outCallType, outArgs); jaroslav@1646: lform = new LambdaForm(debugName, INARG_LIMIT, names); jaroslav@1646: if (isLinker) jaroslav@1646: lform.compileToBytecode(); // JVM needs a real methodOop jaroslav@1646: if (isCached) jaroslav@1646: lform = mtype.form().setCachedLambdaForm(which, lform); jaroslav@1646: return lform; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /*non-public*/ static jaroslav@1646: WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) { jaroslav@1646: // FIXME: merge with JVM logic for throwing WMTE jaroslav@1646: return new WrongMethodTypeException("expected "+expected+" but found "+actual); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Static definition of MethodHandle.invokeExact checking code. */ jaroslav@1646: /*non-public*/ static jaroslav@1646: @ForceInline jaroslav@1646: void checkExactType(Object mhObj, Object expectedObj) { jaroslav@1646: MethodHandle mh = (MethodHandle) mhObj; jaroslav@1646: MethodType expected = (MethodType) expectedObj; jaroslav@1646: MethodType actual = mh.type(); jaroslav@1646: if (actual != expected) jaroslav@1646: throw newWrongMethodTypeException(expected, actual); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Static definition of MethodHandle.invokeGeneric checking code. jaroslav@1646: * Directly returns the type-adjusted MH to invoke, as follows: jaroslav@1646: * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)} jaroslav@1646: */ jaroslav@1646: /*non-public*/ static jaroslav@1646: @ForceInline jaroslav@1646: Object checkGenericType(Object mhObj, Object expectedObj) { jaroslav@1646: MethodHandle mh = (MethodHandle) mhObj; jaroslav@1646: MethodType expected = (MethodType) expectedObj; jaroslav@1646: if (mh.type() == expected) return mh; jaroslav@1646: MethodHandle atc = mh.asTypeCache; jaroslav@1646: if (atc != null && atc.type() == expected) return atc; jaroslav@1646: return mh.asType(expected); jaroslav@1646: /* Maybe add more paths here. Possible optimizations: jaroslav@1646: * for (R)MH.invoke(a*), jaroslav@1646: * let MT0 = TYPEOF(a*:R), MT1 = MH.type jaroslav@1646: * jaroslav@1646: * if MT0==MT1 or MT1 can be safely called by MT0 jaroslav@1646: * => MH.invokeBasic(a*) jaroslav@1646: * if MT1 can be safely called by MT0[R := Object] jaroslav@1646: * => MH.invokeBasic(a*) & checkcast(R) jaroslav@1646: * if MT1 can be safely called by MT0[* := Object] jaroslav@1646: * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R) jaroslav@1646: * if a big adapter BA can be pulled out of (MT0,MT1) jaroslav@1646: * => BA.invokeBasic(MT0,MH,a*) jaroslav@1646: * if a local adapter LA can cached on static CS0 = new GICS(MT0) jaroslav@1646: * => CS0.LA.invokeBasic(MH,a*) jaroslav@1646: * else jaroslav@1646: * => MH.asType(MT0).invokeBasic(A*) jaroslav@1646: */ jaroslav@1646: } jaroslav@1646: jaroslav@1646: static MemberName linkToCallSiteMethod(MethodType mtype) { jaroslav@1646: LambdaForm lform = callSiteForm(mtype, false); jaroslav@1646: return lform.vmentry; jaroslav@1646: } jaroslav@1646: jaroslav@1646: static MemberName linkToTargetMethod(MethodType mtype) { jaroslav@1646: LambdaForm lform = callSiteForm(mtype, true); jaroslav@1646: return lform.vmentry; jaroslav@1646: } jaroslav@1646: jaroslav@1646: // skipCallSite is true if we are optimizing a ConstantCallSite jaroslav@1646: private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { jaroslav@1646: mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. jaroslav@1646: final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); jaroslav@1646: LambdaForm lform = mtype.form().cachedLambdaForm(which); jaroslav@1646: if (lform != null) return lform; jaroslav@1646: // exactInvokerForm (Object,Object)Object jaroslav@1646: // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial jaroslav@1646: final int ARG_BASE = 0; jaroslav@1646: final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); jaroslav@1646: final int INARG_LIMIT = OUTARG_LIMIT + 1; jaroslav@1646: int nameCursor = OUTARG_LIMIT; jaroslav@1646: final int APPENDIX_ARG = nameCursor++; // the last in-argument jaroslav@1646: final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG; jaroslav@1646: final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget jaroslav@1646: final int LINKER_CALL = nameCursor++; jaroslav@1646: MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class); jaroslav@1646: Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); jaroslav@1646: assert(names.length == nameCursor); jaroslav@1646: assert(names[APPENDIX_ARG] != null); jaroslav@1646: if (!skipCallSite) jaroslav@1646: names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); jaroslav@1646: // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*) jaroslav@1646: final int PREPEND_MH = 0, PREPEND_COUNT = 1; jaroslav@1646: Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class); jaroslav@1646: // prepend MH argument: jaroslav@1646: System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); jaroslav@1646: outArgs[PREPEND_MH] = names[CALL_MH]; jaroslav@1646: names[LINKER_CALL] = new Name(mtype, outArgs); jaroslav@1646: lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names); jaroslav@1646: lform.compileToBytecode(); // JVM needs a real methodOop jaroslav@1646: lform = mtype.form().setCachedLambdaForm(which, lform); jaroslav@1646: return lform; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** Static definition of MethodHandle.invokeGeneric checking code. */ jaroslav@1646: /*non-public*/ static jaroslav@1646: @ForceInline jaroslav@1646: Object getCallSiteTarget(Object site) { jaroslav@1646: return ((CallSite)site).getTarget(); jaroslav@1646: } jaroslav@1646: jaroslav@1646: // Local constant functions: jaroslav@1646: private static final NamedFunction NF_checkExactType; jaroslav@1646: private static final NamedFunction NF_checkGenericType; jaroslav@1646: private static final NamedFunction NF_asType; jaroslav@1646: private static final NamedFunction NF_getCallSiteTarget; jaroslav@1646: static { jaroslav@1646: try { jaroslav@1646: NF_checkExactType = new NamedFunction(Invokers.class jaroslav@1646: .getDeclaredMethod("checkExactType", Object.class, Object.class)); jaroslav@1646: NF_checkGenericType = new NamedFunction(Invokers.class jaroslav@1646: .getDeclaredMethod("checkGenericType", Object.class, Object.class)); jaroslav@1646: NF_asType = new NamedFunction(MethodHandle.class jaroslav@1646: .getDeclaredMethod("asType", MethodType.class)); jaroslav@1646: NF_getCallSiteTarget = new NamedFunction(Invokers.class jaroslav@1646: .getDeclaredMethod("getCallSiteTarget", Object.class)); jaroslav@1646: NF_checkExactType.resolve(); jaroslav@1646: NF_checkGenericType.resolve(); jaroslav@1646: NF_getCallSiteTarget.resolve(); jaroslav@1646: // bound jaroslav@1646: } catch (ReflectiveOperationException ex) { jaroslav@1646: throw newInternalError(ex); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: }