< prev index next >

src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java

Print this page
@@ -76,13 +76,14 @@
  
      // Factory methods:
      static DirectMethodHandle make(byte refKind, Class<?> refc, MemberName member, Class<?> callerClass) {
          MethodType mtype = member.getMethodOrFieldType();
          if (!member.isStatic()) {
-             if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor())
+             if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isObjectConstructor())
                  throw new InternalError(member.toString());
-             mtype = mtype.insertParameterTypes(0, refc);
+             Class<?> receiverType = refc.isPrimitiveClass() ? refc.asValueType() : refc;
+             mtype = mtype.insertParameterTypes(0, receiverType);
          }
          if (!member.isField()) {
              // refKind reflects the original type of lookup via findSpecial or
              // findVirtual etc.
              return switch (refKind) {

@@ -126,19 +127,20 @@
          if (refKind == REF_invokeSpecial)
              refKind =  REF_invokeVirtual;
          return make(refKind, refc, member, null /* no callerClass context */);
      }
      static DirectMethodHandle make(MemberName member) {
-         if (member.isConstructor())
+         if (member.isObjectConstructor() && member.getReturnType() == void.class)
              return makeAllocator(member);
          return make(member.getDeclaringClass(), member);
      }
      private static DirectMethodHandle makeAllocator(MemberName ctor) {
-         assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
+         assert(ctor.isObjectConstructor() && !ctor.getDeclaringClass().isPrimitiveClass()) : ctor;
+ 
          Class<?> instanceClass = ctor.getDeclaringClass();
-         ctor = ctor.asConstructor();
-         assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
+         ctor = ctor.asObjectConstructor();
+         assert(ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
          MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
          LambdaForm lform = preparedLambdaForm(ctor);
          MemberName init = ctor.asSpecial();
          assert(init.getMethodType().returnType() == void.class);
          return new Constructor(mtype, lform, ctor, true, init, instanceClass);

@@ -536,15 +538,14 @@
          // Since this check is *not* guaranteed by Unsafe.getInt
          // and its siblings, we need to make an explicit one here.
          return Objects.requireNonNull(obj);
      }
  
-     /** This subclass handles static field references. */
      static class StaticAccessor extends DirectMethodHandle {
-         private final Class<?> fieldType;
-         private final Object   staticBase;
-         private final long     staticOffset;
+         final Class<?> fieldType;
+         final Object staticBase;
+         final long staticOffset;
  
          private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
                                 boolean crackable, Object staticBase, long staticOffset) {
              super(mtype, form, member, crackable);
              this.fieldType    = member.getFieldType();

@@ -588,10 +589,20 @@
      /*non-public*/
      static Object checkCast(Object mh, Object obj) {
          return ((DirectMethodHandle) mh).checkCast(obj);
      }
  
+     @ForceInline
+     /*non-public*/ static Class<?> fieldType(Object accessorObj) {
+         return ((Accessor) accessorObj).fieldType;
+     }
+ 
+     @ForceInline
+     /*non-public*/ static Class<?> staticFieldType(Object accessorObj) {
+         return ((StaticAccessor) accessorObj).fieldType;
+     }
+ 
      Object checkCast(Object obj) {
          return member.getReturnType().cast(obj);
      }
  
      // Caching machinery for field accessors:

@@ -602,31 +613,34 @@
              AF_PUTSTATIC       = 3,
              AF_GETSTATIC_INIT  = 4,
              AF_PUTSTATIC_INIT  = 5,
              AF_LIMIT           = 6;
      // Enumerate the different field kinds using Wrapper,
-     // with an extra case added for checked references.
+     // with an extra case added for checked references and value field access
      static final int
-             FT_LAST_WRAPPER    = Wrapper.COUNT-1,
-             FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
-             FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
-             FT_LIMIT           = FT_LAST_WRAPPER+2;
-     private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
+             FT_LAST_WRAPPER     = Wrapper.COUNT-1,
+             FT_UNCHECKED_REF    = Wrapper.OBJECT.ordinal(),
+             FT_CHECKED_REF      = FT_LAST_WRAPPER+1,
+             FT_CHECKED_VALUE    = FT_LAST_WRAPPER+2,  // flattened and non-flattened
+             FT_LIMIT            = FT_LAST_WRAPPER+4;
+     private static int afIndex(byte formOp, boolean isVolatile, boolean isFlatValue, int ftypeKind) {
          return ((formOp * FT_LIMIT * 2)
                  + (isVolatile ? FT_LIMIT : 0)
+                 + (isFlatValue ? 1 : 0)
                  + ftypeKind);
      }
      @Stable
      private static final LambdaForm[] ACCESSOR_FORMS
-             = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
-     static int ftypeKind(Class<?> ftype) {
+             = new LambdaForm[afIndex(AF_LIMIT, false, false, 0)];
+     static int ftypeKind(Class<?> ftype, boolean isValue) {
          if (ftype.isPrimitive())
              return Wrapper.forPrimitiveType(ftype).ordinal();
-         else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
+         else if (VerifyType.isNullReferenceConversion(Object.class, ftype)) {
              return FT_UNCHECKED_REF;
-         else
-             return FT_CHECKED_REF;
+         } else
+             // null check for value type in addition to check cast
+             return isValue ? FT_CHECKED_VALUE : FT_CHECKED_REF;
      }
  
      /**
       * Create a LF which can access the given field.
       * Cache and share this structure among all fields with

@@ -642,35 +656,36 @@
              case REF_putStatic -> AF_PUTSTATIC;
              default -> throw new InternalError(m.toString());
          };
          if (shouldBeInitialized(m)) {
              // precompute the barrier-free version:
-             preparedFieldLambdaForm(formOp, isVolatile, ftype);
+             preparedFieldLambdaForm(formOp, m.isVolatile(), m.isInlineableField(), m.isFlattened(), ftype);
              assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
                     (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
              formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
          }
-         LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
+         LambdaForm lform = preparedFieldLambdaForm(formOp, m.isVolatile(), m.isInlineableField(), m.isFlattened(), 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;
      }
-     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
-         int ftypeKind = ftypeKind(ftype);
-         int afIndex = afIndex(formOp, isVolatile, ftypeKind);
+ 
+     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, boolean isValue, boolean isFlatValue, Class<?> ftype) {
+         int ftypeKind = ftypeKind(ftype, isValue);
+         int afIndex = afIndex(formOp, isVolatile, isFlatValue, ftypeKind);
          LambdaForm lform = ACCESSOR_FORMS[afIndex];
          if (lform != null)  return lform;
-         lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
+         lform = makePreparedFieldLambdaForm(formOp, isVolatile, isValue, isFlatValue, ftypeKind);
          ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
          return lform;
      }
  
      private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
  
-     private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
+     private static Kind getFieldKind(boolean isGetter, boolean isVolatile, boolean isFlatValue, Wrapper wrapper) {
          if (isGetter) {
              if (isVolatile) {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN_VOLATILE;
                      case BYTE:    return GET_BYTE_VOLATILE;

@@ -678,11 +693,11 @@
                      case CHAR:    return GET_CHAR_VOLATILE;
                      case INT:     return GET_INT_VOLATILE;
                      case LONG:    return GET_LONG_VOLATILE;
                      case FLOAT:   return GET_FLOAT_VOLATILE;
                      case DOUBLE:  return GET_DOUBLE_VOLATILE;
-                     case OBJECT:  return GET_REFERENCE_VOLATILE;
+                     case OBJECT:  return isFlatValue ? GET_VALUE_VOLATILE : GET_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN;
                      case BYTE:    return GET_BYTE;

@@ -690,11 +705,11 @@
                      case CHAR:    return GET_CHAR;
                      case INT:     return GET_INT;
                      case LONG:    return GET_LONG;
                      case FLOAT:   return GET_FLOAT;
                      case DOUBLE:  return GET_DOUBLE;
-                     case OBJECT:  return GET_REFERENCE;
+                     case OBJECT:  return isFlatValue ? GET_VALUE : GET_REFERENCE;
                  }
              }
          } else {
              if (isVolatile) {
                  switch (wrapper) {

@@ -704,11 +719,11 @@
                      case CHAR:    return PUT_CHAR_VOLATILE;
                      case INT:     return PUT_INT_VOLATILE;
                      case LONG:    return PUT_LONG_VOLATILE;
                      case FLOAT:   return PUT_FLOAT_VOLATILE;
                      case DOUBLE:  return PUT_DOUBLE_VOLATILE;
-                     case OBJECT:  return PUT_REFERENCE_VOLATILE;
+                     case OBJECT:  return isFlatValue ? PUT_VALUE_VOLATILE : PUT_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return PUT_BOOLEAN;
                      case BYTE:    return PUT_BYTE;

@@ -716,34 +731,43 @@
                      case CHAR:    return PUT_CHAR;
                      case INT:     return PUT_INT;
                      case LONG:    return PUT_LONG;
                      case FLOAT:   return PUT_FLOAT;
                      case DOUBLE:  return PUT_DOUBLE;
-                     case OBJECT:  return PUT_REFERENCE;
+                     case OBJECT:  return isFlatValue ? PUT_VALUE : PUT_REFERENCE;
                  }
              }
          }
          throw new AssertionError("Invalid arguments");
      }
  
-     static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
+     /** invoked by GenerateJLIClassesHelper */
+     static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftype) {
+         return makePreparedFieldLambdaForm(formOp, isVolatile, false, false, ftype);
+     }
+ 
+     private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, boolean isValue, boolean isFlatValue, 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);
+         boolean needsCast = (ftypeKind == FT_CHECKED_REF || ftypeKind == FT_CHECKED_VALUE);
          Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
          Class<?> ft = fw.primitiveType();
-         assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
+         assert(needsCast ? true : ftypeKind(ft, isValue) == ftypeKind);
  
          // getObject, putIntVolatile, etc.
-         Kind kind = getFieldKind(isGetter, isVolatile, fw);
+         Kind kind = getFieldKind(isGetter, isVolatile, isFlatValue, fw);
  
          MethodType linkerType;
-         if (isGetter)
-             linkerType = MethodType.methodType(ft, Object.class, long.class);
-         else
-             linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
+         boolean hasValueTypeArg = isGetter ? isValue : isFlatValue;
+         if (isGetter) {
+             linkerType = isValue ? MethodType.methodType(ft, Object.class, long.class, Class.class)
+                                  : MethodType.methodType(ft, Object.class, long.class);
+         } else {
+             linkerType = isFlatValue ? MethodType.methodType(void.class, Object.class, long.class, Class.class, ft)
+                                      : MethodType.methodType(void.class, Object.class, long.class, ft);
+         }
          MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
          try {
              linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
                                                NoSuchMethodException.class);
          } catch (ReflectiveOperationException ex) {

@@ -770,31 +794,37 @@
          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 U_HOLDER  = nameCursor++;  // UNSAFE holder
          final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
+         final int VALUE_TYPE = (hasValueTypeArg ? 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(getFunction(NF_ensureInitialized), names[DMH_THIS]);
          if (needsCast && !isGetter)
              names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
          Object[] outArgs = new Object[1 + linkerType.parameterCount()];
-         assert(outArgs.length == (isGetter ? 3 : 4));
+         assert (outArgs.length == (isGetter ? 3 : 4) + (hasValueTypeArg ? 1 : 0));
          outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
          if (isStatic) {
              outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
          } else {
              outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
          }
+         int x = 3;
+         if (hasValueTypeArg) {
+             outArgs[x++] = names[VALUE_TYPE] = isStatic ? new Name(getFunction(NF_staticFieldType), names[DMH_THIS])
+                                                         : new Name(getFunction(NF_fieldType), names[DMH_THIS]);
+         }
          if (!isGetter) {
-             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
+             outArgs[x] = (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(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);

@@ -841,11 +871,13 @@
              NF_checkCast = 7,
              NF_allocateInstance = 8,
              NF_constructorMethod = 9,
              NF_UNSAFE = 10,
              NF_checkReceiver = 11,
-             NF_LIMIT = 12;
+             NF_fieldType = 12,
+             NF_staticFieldType = 13,
+             NF_LIMIT = 14;
  
      private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
  
      private static NamedFunction getFunction(byte func) {
          NamedFunction nf = NFS[func];

@@ -856,10 +888,12 @@
          nf = NFS[func] = createFunction(func);
          assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
          return nf;
      }
  
+     private static final MethodType CLS_OBJ_TYPE = MethodType.methodType(Class.class, Object.class);
+ 
      private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
  
      private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
  
      private static NamedFunction createFunction(byte func) {

@@ -892,13 +926,17 @@
                                                                    DirectMethodHandle.class, LM_TRUSTED,
                                                                    NoSuchMethodException.class));
                  case NF_checkReceiver:
                      member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
                      return new NamedFunction(
-                             MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
-                                                                   DirectMethodHandle.class, LM_TRUSTED,
-                                                                   NoSuchMethodException.class));
+                         MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
+                                                               DirectMethodHandle.class, LM_TRUSTED,
+                                                               NoSuchMethodException.class));
+                 case NF_fieldType:
+                     return getNamedFunction("fieldType", CLS_OBJ_TYPE);
+                 case NF_staticFieldType:
+                     return getNamedFunction("staticFieldType", CLS_OBJ_TYPE);
                  default:
                      throw newInternalError("Unknown function: " + func);
              }
          } catch (ReflectiveOperationException ex) {
              throw newInternalError(ex);
< prev index next >