Exemplo n.º 1
0
  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);
  }