< prev index next >

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

Print this page

        

@@ -102,15 +102,18 @@
         } 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);
+                return member.isFlattenable() ? new StaticValueAccessor(mtype, lform, member, base, offset)
+                                              : 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);
+                return  member.isFlattenable() ? new ValueAccessor(mtype, lform, member, (int)offset)
+                                               : new Accessor(mtype, lform, member, (int)offset);
+
             }
         }
     }
     static DirectMethodHandle make(Class<?> refc, MemberName member) {
         byte refKind = member.getReferenceKind();

@@ -488,10 +491,25 @@
         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
             return new Accessor(mt, lf, member, fieldOffset);
         }
     }
 
+    static class ValueAccessor extends Accessor {
+        private ValueAccessor(MethodType mtype, LambdaForm form, MemberName member,
+                              int fieldOffset) {
+            super(mtype, form, member, fieldOffset);
+        }
+
+        @Override Object checkCast(Object obj) {
+            return fieldType.cast(Objects.requireNonNull(obj));
+        }
+        @Override
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new ValueAccessor(mt, lf, member, fieldOffset);
+        }
+    }
+
     @ForceInline
     /*non-public*/ static long fieldOffset(Object accessorObj) {
         // Note: We return a long because that is what Unsafe.getObject likes.
         // We store a plain int because it is more compact.
         return ((Accessor)accessorObj).fieldOffset;

@@ -509,13 +527,13 @@
         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,
                                Object staticBase, long staticOffset) {
             super(mtype, form, member);
             this.fieldType    = member.getFieldType();

@@ -530,10 +548,26 @@
         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
             return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
         }
     }
 
+    static class StaticValueAccessor extends StaticAccessor {
+        private StaticValueAccessor(MethodType mtype, LambdaForm form, MemberName member,
+                               Object staticBase, long staticOffset) {
+            super(mtype, form, member, staticBase, staticOffset);
+        }
+
+        @Override Object checkCast(Object obj) {
+            return fieldType.cast(Objects.requireNonNull(obj));
+        }
+        @Override
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new StaticValueAccessor(mt, lf, member, staticBase, staticOffset);
+        }
+    }
+
+
     @ForceInline
     /*non-public*/ static Object nullCheck(Object obj) {
         return Objects.requireNonNull(obj);
     }
 

@@ -574,42 +608,45 @@
             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 isFlattened, boolean isVolatile, int ftypeKind) {
+            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 isFlattened, int ftypeKind) {
         return ((formOp * FT_LIMIT * 2)
-                + (isFlattened ? FT_LIMIT : 0)
                 + (isVolatile ? FT_LIMIT : 0)
+                + (isFlattened ? 1 : 0)
                 + ftypeKind);
     }
     @Stable
     private static final LambdaForm[] ACCESSOR_FORMS
-            = new LambdaForm[afIndex(AF_LIMIT, false,false, 0)];
-    static int ftypeKind(Class<?> ftype) {
+            = new LambdaForm[afIndex(AF_LIMIT, false, false, 0)];
+    static int ftypeKind(Class<?> ftype, boolean isNullable) {
         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 isNullable ? FT_CHECKED_REF : FT_CHECKED_VALUE;
     }
 
     /**
      * 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();
+        boolean isNullable = m.isNullable();
         boolean isFlattened = m.isFlattened();
         byte formOp;
         switch (m.getReferenceKind()) {
         case REF_getField:      formOp = AF_GETFIELD;    break;
         case REF_putField:      formOp = AF_PUTFIELD;    break;

@@ -617,36 +654,37 @@
         case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
         default:  throw new InternalError(m.toString());
         }
         if (shouldBeInitialized(m)) {
             // precompute the barrier-free version:
-            preparedFieldLambdaForm(formOp, isFlattened, isVolatile, ftype);
+            preparedFieldLambdaForm(formOp, isVolatile, isFlattened, isNullable, ftype);
             assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
                    (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
             formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
         }
-        LambdaForm lform = preparedFieldLambdaForm(formOp, isFlattened, isVolatile, ftype);
+        LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, isFlattened, isNullable, 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 isFlattened, boolean isVolatile, Class<?> ftype) {
-        int ftypeKind = ftypeKind(ftype);
-        int afIndex = afIndex(formOp, isFlattened, isVolatile, ftypeKind);
+    private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, boolean isFlattened, boolean isNullable, Class<?> ftype) {
+        int ftypeKind = ftypeKind(ftype, isNullable);
+        assert(isNullable ? (ftypeKind < FT_CHECKED_VALUE) : (ftypeKind == FT_CHECKED_VALUE));
+        int afIndex = afIndex(formOp, isVolatile, isFlattened, ftypeKind);
         LambdaForm lform = ACCESSOR_FORMS[afIndex];
         if (lform != null)  return lform;
-        lform = makePreparedFieldLambdaForm(formOp, isFlattened, isVolatile, ftypeKind);
+        lform = makePreparedFieldLambdaForm(formOp, isVolatile, isFlattened, 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 isFlattened, boolean isVolatile, Wrapper wrapper) {
+    private static Kind getFieldKind(boolean isGetter, boolean isVolatile, boolean isFlattened, Wrapper wrapper) {
         if (isGetter) {
             if (isVolatile) {
                 switch (wrapper) {
                     case BOOLEAN: return GET_BOOLEAN_VOLATILE;
                     case BYTE:    return GET_BYTE_VOLATILE;

@@ -654,11 +692,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 isFlattened ? GET_VALUE_VOLATILE : GET_REFERENCE_VOLATILE;
                 }
             } else {
                 switch (wrapper) {
                     case BOOLEAN: return GET_BOOLEAN;
                     case BYTE:    return GET_BYTE;

@@ -680,11 +718,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 isFlattened ? PUT_VALUE_VOLATILE : PUT_REFERENCE_VOLATILE;
                 }
             } else {
                 switch (wrapper) {
                     case BOOLEAN: return PUT_BOOLEAN;
                     case BYTE:    return PUT_BYTE;

@@ -699,21 +737,21 @@
             }
         }
         throw new AssertionError("Invalid arguments");
     }
 
-    static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isFlattened, boolean isVolatile, int ftypeKind) {
+    static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, boolean isFlattened, 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, ftypeKind != FT_CHECKED_VALUE) == ftypeKind);
 
         // getObject, putIntVolatile, etc.
-        Kind kind = getFieldKind(isGetter, isFlattened, isVolatile, fw);
+        Kind kind = getFieldKind(isGetter, isVolatile, isFlattened, fw);
 
         MethodType linkerType;
         if (isFlattened) {
             linkerType = isGetter ? MethodType.methodType(ft, Object.class, long.class, Class.class)
                                   : MethodType.methodType(void.class, Object.class, long.class, Class.class, ft);
< prev index next >