/**
  * Create a LF which can access the given field. Cache and share this structure among all fields
  * with the same basicType and refKind.
  */
 private static LambdaForm preparedFieldLambdaForm(MemberName m) {
   Class<?> ftype = m.getFieldType();
   boolean isVolatile = m.isVolatile();
   byte formOp;
   switch (m.getReferenceKind()) {
     case REF_getField:
       formOp = AF_GETFIELD;
       break;
     case REF_putField:
       formOp = AF_PUTFIELD;
       break;
     case REF_getStatic:
       formOp = AF_GETSTATIC;
       break;
     case REF_putStatic:
       formOp = AF_PUTSTATIC;
       break;
     default:
       throw new InternalError(m.toString());
   }
   if (shouldBeInitialized(m)) {
     // precompute the barrier-free version:
     preparedFieldLambdaForm(formOp, isVolatile, ftype);
     assert ((AF_GETSTATIC_INIT - AF_GETSTATIC) == (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
     formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
   }
   LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
   maybeCompile(lform, m);
   assert (lform.methodType().dropParameterTypes(0, 1).equals(m.getInvocationType().basicType()))
       : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   return lform;
 }
 /**
  * Create a LF which can invoke the given method. Cache and share this structure among all methods
  * with the same basicType and refKind.
  */
 private static LambdaForm preparedLambdaForm(MemberName m) {
   assert (m.isInvocable()) : m; // call preparedFieldLambdaForm instead
   MethodType mtype = m.getInvocationType().basicType();
   assert (!m.isMethodHandleInvoke()) : m;
   int which;
   switch (m.getReferenceKind()) {
     case REF_invokeVirtual:
       which = LF_INVVIRTUAL;
       break;
     case REF_invokeStatic:
       which = LF_INVSTATIC;
       break;
     case REF_invokeSpecial:
       which = LF_INVSPECIAL;
       break;
     case REF_invokeInterface:
       which = LF_INVINTERFACE;
       break;
     case REF_newInvokeSpecial:
       which = LF_NEWINVSPECIAL;
       break;
     default:
       throw new InternalError(m.toString());
   }
   if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
     // precompute the barrier-free version:
     preparedLambdaForm(mtype, which);
     which = LF_INVSTATIC_INIT;
   }
   LambdaForm lform = preparedLambdaForm(mtype, which);
   maybeCompile(lform, m);
   assert (lform.methodType().dropParameterTypes(0, 1).equals(m.getInvocationType().basicType()))
       : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   return lform;
 }
 private static void maybeCompile(LambdaForm lform, MemberName m) {
   if (lform.vmentry == null
       && VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
     // Help along bootstrapping...
     lform.compileToBytecode();
 }
  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;
  }