< prev index next >

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

Print this page
@@ -24,10 +24,12 @@
   */
  
  package java.lang.invoke;
  
  import jdk.internal.misc.CDS;
+ import jdk.internal.value.ValueClass;
+ import jdk.internal.vm.annotation.LooselyConsistentValue;
  import sun.invoke.util.Wrapper;
  
  import java.lang.foreign.MemoryLayout;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;

@@ -49,13 +51,40 @@
      static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAllowedOnFinalFields) {
          if (!f.isStatic()) {
              long foffset = MethodHandleNatives.objectFieldOffset(f);
              Class<?> type = f.getFieldType();
              if (!type.isPrimitive()) {
-                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
-                        ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type)
-                        : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type));
+                 if (type.isValue()) {
+                     int layout = f.getLayout();
+                     boolean isAtomic = isAtomicFlat(f);
+                     boolean isFlat = f.isFlat();
+                     if (isFlat) {
+                         if (isAtomic) {
+                             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                                     ? new VarHandleFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
+                                     : new VarHandleFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
+                         } else {
+                             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                                     ? new VarHandleNonAtomicFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
+                                     : new VarHandleNonAtomicFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
+                         }
+                     } else {
+                         if (isAtomic) {
+                             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                                     ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
+                                     : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
+                         } else {
+                             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                                     ? new VarHandleNonAtomicReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
+                                     : new VarHandleNonAtomicReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
+                         }
+                     }
+                 } else {
+                     return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                        ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
+                        : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
+                 }
              }
              else if (type == boolean.class) {
                  return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
                         ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset)
                         : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset));

@@ -111,13 +140,26 @@
      static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean isWriteAllowedOnFinalFields) {
          Object base = MethodHandleNatives.staticFieldBase(f);
          long foffset = MethodHandleNatives.staticFieldOffset(f);
          Class<?> type = f.getFieldType();
          if (!type.isPrimitive()) {
-             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
-                     ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type)
-                     : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type));
+             assert !f.isFlat() : ("static field is flat in " + decl + "." + f.getName());
+             if (type.isValue()) {
+                 if (isAtomicFlat(f)) {
+                     return f.isFinal() && !isWriteAllowedOnFinalFields
+                             ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
+                             : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
+                 } else {
+                     return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
+                             ? new VarHandleNonAtomicReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
+                             : new VarHandleNonAtomicReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted()));
+                 }
+             } else {
+                 return f.isFinal() && !isWriteAllowedOnFinalFields
+                         ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
+                         : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
+             }
          }
          else if (type == boolean.class) {
              return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
                      ? new VarHandleBooleans.FieldStaticReadOnly(decl, base, foffset)
                      : new VarHandleBooleans.FieldStaticReadWrite(decl, base, foffset));

@@ -160,10 +202,40 @@
          else {
              throw new UnsupportedOperationException();
          }
      }
  
+     static boolean isAtomicFlat(MemberName field) {
+         boolean hasAtomicAccess = (field.getModifiers() & Modifier.VOLATILE) != 0 ||
+                 !(field.isNullRestricted()) ||
+                 !field.getFieldType().isAnnotationPresent(LooselyConsistentValue.class);
+         return hasAtomicAccess && !HAS_OOPS.get(field.getFieldType());
+     }
+ 
+     static boolean isAtomicFlat(Object[] array) {
+         Class<?> componentType = array.getClass().componentType();
+         boolean hasAtomicAccess = ValueClass.isAtomicArray(array) ||
+                 !ValueClass.isNullRestrictedArray(array) ||
+                 !componentType.isAnnotationPresent(LooselyConsistentValue.class);
+         return hasAtomicAccess && !HAS_OOPS.get(componentType);
+     }
+ 
+     static final ClassValue<Boolean> HAS_OOPS = new ClassValue<>() {
+         @Override
+         protected Boolean computeValue(Class<?> c) {
+             for (Field f : c.getDeclaredFields()) {
+                 Class<?> ftype = f.getType();
+                 if (UNSAFE.isFlatField(f) && HAS_OOPS.get(ftype)) {
+                     return true;
+                 } else if (!ftype.isPrimitive()) {
+                     return true;
+                 }
+             }
+             return false;
+         }
+     };
+ 
      // Required by instance field handles
      static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
                                                 long offset,
                                                 Class<?> fieldType) {
          for (Field f : receiverType.getDeclaredFields()) {

@@ -190,10 +262,17 @@
              }
          }
          throw new InternalError("Static field not found at offset");
      }
  
+     // This is invoked by non-flat array var handle code when attempting to access a flat array
+     public static void checkAtomicFlatArray(Object[] array) {
+         if (!isAtomicFlat(array)) {
+             throw new IllegalArgumentException("Attempt to perform a non-plain access on a non-atomic array");
+         }
+     }
+ 
      static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
          if (!arrayClass.isArray())
              throw new IllegalArgumentException("not an array: " + arrayClass);
  
          Class<?> componentType = arrayClass.getComponentType();

@@ -201,10 +280,14 @@
          int aoffset = (int) UNSAFE.arrayBaseOffset(arrayClass);
          int ascale = UNSAFE.arrayIndexScale(arrayClass);
          int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
  
          if (!componentType.isPrimitive()) {
+             // Here we always return a reference array element var handle. This is because
+             // the access semantics is determined at runtime, when an actual array object is passed
+             // to the var handle. The var handle implementation will switch to use flat access
+             // primitives if it sees a flat array.
              return maybeAdapt(new VarHandleReferences.Array(aoffset, ashift, arrayClass));
          }
          else if (componentType == boolean.class) {
              return maybeAdapt(new VarHandleBooleans.Array(aoffset, ashift));
          }
< prev index next >