changeset 36337:d4b2f60ff5a9

8150543: Mismatched access detection is inaccurate Reviewed-by: kvn, shade
author vlivanov
date Mon, 29 Feb 2016 23:46:55 +0300
parents 7006dd73b206
children de236db57636
files hotspot/src/share/vm/opto/library_call.cpp hotspot/src/share/vm/opto/memnode.cpp hotspot/test/compiler/unsafe/UnsafeGetConstantField.java hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java
diffstat 4 files changed, 284 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/share/vm/opto/library_call.cpp	Mon Feb 29 15:05:45 2016 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Mon Feb 29 23:46:55 2016 +0300
@@ -2541,10 +2541,12 @@
   if (alias_type->element() != NULL || alias_type->field() != NULL) {
     BasicType bt;
     if (alias_type->element() != NULL) {
-      const Type* element = alias_type->element();
+      // Use address type to get the element type. Alias type doesn't provide
+      // enough information (e.g., doesn't differentiate between byte[] and boolean[]).
+      const Type* element = adr_type->is_aryptr()->elem();
       bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type();
     } else {
-      bt = alias_type->field()->type()->basic_type();
+      bt = alias_type->field()->layout_type();
     }
     if (bt == T_ARRAY) {
       // accessing an array field with getObject is not a mismatch
@@ -2561,7 +2563,7 @@
     // Try to constant fold a load from a constant field
     ciField* field = alias_type->field();
     if (heap_base_oop != top() &&
-        field != NULL && field->is_constant() && field->layout_type() == type) {
+        field != NULL && field->is_constant() && !mismatched) {
       // final or stable field
       const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop);
       if (con_type != NULL) {
--- a/hotspot/src/share/vm/opto/memnode.cpp	Mon Feb 29 15:05:45 2016 +0100
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Mon Feb 29 23:46:55 2016 +0300
@@ -1582,14 +1582,22 @@
   return NULL;
 }
 
+#ifdef ASSERT
 static bool is_mismatched_access(ciConstant con, BasicType loadbt) {
   BasicType conbt = con.basic_type();
-  assert(conbt != T_NARROWOOP, "sanity");
-  if (loadbt == T_NARROWOOP || loadbt == T_ARRAY) {
-    loadbt = T_OBJECT;
+  switch (conbt) {
+    case T_BOOLEAN: conbt = T_BYTE;   break;
+    case T_ARRAY:   conbt = T_OBJECT; break;
+  }
+  switch (loadbt) {
+    case T_BOOLEAN:   loadbt = T_BYTE;   break;
+    case T_NARROWOOP: loadbt = T_OBJECT; break;
+    case T_ARRAY:     loadbt = T_OBJECT; break;
+    case T_ADDRESS:   loadbt = T_OBJECT; break;
   }
   return (conbt != loadbt);
 }
+#endif // ASSERT
 
 // Try to constant-fold a stable array element.
 static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
@@ -1599,7 +1607,9 @@
   // Decode the results of GraphKit::array_element_address.
   ciArray* aobj = ary->const_oop()->as_array();
   ciConstant con = aobj->element_value_by_offset(off);
-  if (con.basic_type() != T_ILLEGAL && !is_mismatched_access(con, loadbt) && !con.is_null_or_zero()) {
+  if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+    assert(!is_mismatched_access(con, loadbt),
+           "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt));
     const Type* con_type = Type::make_from_constant(con);
     if (con_type != NULL) {
       if (con_type->isa_aryptr()) {
--- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java	Mon Feb 29 15:05:45 2016 +0100
+++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java	Mon Feb 29 23:46:55 2016 +0300
@@ -27,6 +27,9 @@
  * @test
  * @summary tests on constant folding of unsafe get operations
  * @library /testlibrary /test/lib
+ *
+ * @requires vm.flavor != "client"
+ *
  * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
  *                   -Xbatch -XX:-TieredCompilation
  *                   -XX:+FoldStableValues
--- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java	Mon Feb 29 15:05:45 2016 +0100
+++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java	Mon Feb 29 23:46:55 2016 +0300
@@ -25,17 +25,15 @@
 
 /*
  * @test
- * @summary tests on constant folding of unsafe get operations
+ * @summary tests on constant folding of unsafe get operations from stable arrays
  * @library /testlibrary /test/lib
  *
+ * @requires vm.flavor != "client"
+ *
  * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
  *                   -Xbatch -XX:-TieredCompilation
  *                   -XX:+FoldStableValues
- *                   UnsafeGetStableArrayElement
- *
- * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
- *                   -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1
- *                   -XX:+FoldStableValues
+ *                   -XX:CompileCommand=dontinline,*Test::test*
  *                   UnsafeGetStableArrayElement
  */
 import jdk.internal.misc.Unsafe;
@@ -46,23 +44,271 @@
 import static jdk.test.lib.Asserts.*;
 
 public class UnsafeGetStableArrayElement {
-    @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[] { 0, 1, -128, 127};
+    @Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16];
+    @Stable static final    byte[]    STABLE_BYTE_ARRAY = new    byte[16];
+    @Stable static final   short[]   STABLE_SHORT_ARRAY = new   short[8];
+    @Stable static final    char[]    STABLE_CHAR_ARRAY = new    char[8];
+    @Stable static final     int[]     STABLE_INT_ARRAY = new     int[4];
+    @Stable static final    long[]    STABLE_LONG_ARRAY = new    long[2];
+    @Stable static final   float[]   STABLE_FLOAT_ARRAY = new   float[4];
+    @Stable static final  double[]  STABLE_DOUBLE_ARRAY = new  double[2];
+    @Stable static final  Object[]  STABLE_OBJECT_ARRAY = new  Object[4];
 
+    static {
+        Setter.reset();
+    }
     static final Unsafe U = Unsafe.getUnsafe();
 
-    static int testChar() {
-        return U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 0 * ARRAY_CHAR_INDEX_SCALE) +
-               U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 1 * ARRAY_CHAR_INDEX_SCALE);
-    }
+    static class Setter {
+        private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false :                true; }
+        private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0]    = defaultVal ?     0 :      Byte.MAX_VALUE; }
+        private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0]   = defaultVal ?     0 :     Short.MAX_VALUE; }
+        private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0]    = defaultVal ?     0 : Character.MAX_VALUE; }
+        private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0]     = defaultVal ?     0 :   Integer.MAX_VALUE; }
+        private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0]    = defaultVal ?     0 :      Long.MAX_VALUE; }
+        private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0]   = defaultVal ?     0 :     Float.MAX_VALUE; }
+        private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0]  = defaultVal ?     0 :    Double.MAX_VALUE; }
+        private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0]  = defaultVal ?  null :        new Object(); }
 
-    static void run(Callable c) throws Exception {
-        Object first = c.call();
-        for (int i = 0; i < 20_000; i++) {
-            assertEQ(first, c.call());
+        static void reset() {
+            setZ(false);
+            setB(false);
+            setS(false);
+            setC(false);
+            setI(false);
+            setJ(false);
+            setF(false);
+            setD(false);
+            setL(false);
         }
     }
 
+    static class Test {
+        static void changeZ() { Setter.setZ(true); }
+        static void changeB() { Setter.setB(true); }
+        static void changeS() { Setter.setS(true); }
+        static void changeC() { Setter.setC(true); }
+        static void changeI() { Setter.setI(true); }
+        static void changeJ() { Setter.setJ(true); }
+        static void changeF() { Setter.setF(true); }
+        static void changeD() { Setter.setD(true); }
+        static void changeL() { Setter.setL(true); }
+
+        static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static byte    testZ_B() { return U.getByte(   STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static short   testZ_S() { return U.getShort(  STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static char    testZ_C() { return U.getChar(   STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static int     testZ_I() { return U.getInt(    STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static long    testZ_J() { return U.getLong(   STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static float   testZ_F() { return U.getFloat(  STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+        static double  testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); }
+
+        static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static byte    testB_B() { return U.getByte(   STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static short   testB_S() { return U.getShort(  STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static char    testB_C() { return U.getChar(   STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static int     testB_I() { return U.getInt(    STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static long    testB_J() { return U.getLong(   STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static float   testB_F() { return U.getFloat(  STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+        static double  testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); }
+
+        static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static byte    testS_B() { return U.getByte(   STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static short   testS_S() { return U.getShort(  STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static char    testS_C() { return U.getChar(   STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static int     testS_I() { return U.getInt(    STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static long    testS_J() { return U.getLong(   STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static float   testS_F() { return U.getFloat(  STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+        static double  testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); }
+
+        static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static byte    testC_B() { return U.getByte(   STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static short   testC_S() { return U.getShort(  STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static char    testC_C() { return U.getChar(   STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static int     testC_I() { return U.getInt(    STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static long    testC_J() { return U.getLong(   STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static float   testC_F() { return U.getFloat(  STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+        static double  testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); }
+
+        static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static byte    testI_B() { return U.getByte(   STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static short   testI_S() { return U.getShort(  STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static char    testI_C() { return U.getChar(   STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static int     testI_I() { return U.getInt(    STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static long    testI_J() { return U.getLong(   STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static float   testI_F() { return U.getFloat(  STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+        static double  testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); }
+
+        static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static byte    testJ_B() { return U.getByte(   STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static short   testJ_S() { return U.getShort(  STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static char    testJ_C() { return U.getChar(   STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static int     testJ_I() { return U.getInt(    STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static long    testJ_J() { return U.getLong(   STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static float   testJ_F() { return U.getFloat(  STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+        static double  testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); }
+
+        static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static byte    testF_B() { return U.getByte(   STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static short   testF_S() { return U.getShort(  STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static char    testF_C() { return U.getChar(   STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static int     testF_I() { return U.getInt(    STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static long    testF_J() { return U.getLong(   STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static float   testF_F() { return U.getFloat(  STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+        static double  testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); }
+
+        static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static byte    testD_B() { return U.getByte(   STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static short   testD_S() { return U.getShort(  STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static char    testD_C() { return U.getChar(   STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static int     testD_I() { return U.getInt(    STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static long    testD_J() { return U.getLong(   STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static float   testD_F() { return U.getFloat(  STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+        static double  testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); }
+
+        static Object  testL_L() { return U.getObject( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static byte    testL_B() { return U.getByte(   STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static short   testL_S() { return U.getShort(  STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static char    testL_C() { return U.getChar(   STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static int     testL_I() { return U.getInt(    STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static long    testL_J() { return U.getLong(   STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static float   testL_F() { return U.getFloat(  STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+        static double  testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); }
+
+        static short   testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); }
+        static char    testC_U() { return U.getCharUnaligned(  STABLE_CHAR_ARRAY,  ARRAY_CHAR_BASE_OFFSET + 1); }
+        static int     testI_U() { return U.getIntUnaligned(    STABLE_INT_ARRAY,   ARRAY_INT_BASE_OFFSET + 1); }
+        static long    testJ_U() { return U.getLongUnaligned(  STABLE_LONG_ARRAY,  ARRAY_LONG_BASE_OFFSET + 1); }
+    }
+
+    static void run(Callable<?> c, Runnable sameResultAction, Runnable changeResultAction) throws Exception {
+        Object first = c.call();
+
+        // Trigger compilation.
+        for (int i = 0; i < 20_000; i++) {
+            // Don't compare results here, since most of Test::testL_* results vary across iterations (due to GC).
+            c.call();
+        }
+
+        if (sameResultAction != null) {
+            sameResultAction.run();
+            assertEQ(first, c.call());
+        }
+
+        if (changeResultAction != null) {
+            changeResultAction.run();
+            assertNE(first, c.call());
+            assertEQ(c.call(), c.call());
+        }
+    }
+
+    static void testMatched(Callable<?> c, Runnable setDefaultAction) throws Exception {
+        run(c, setDefaultAction, null);
+        Setter.reset();
+    }
+
+    static void testMismatched(Callable<?> c, Runnable setDefaultAction) throws Exception {
+        run(c, null, setDefaultAction);
+        Setter.reset();
+    }
+
     public static void main(String[] args) throws Exception {
-        run(UnsafeGetStableArrayElement::testChar);
+        // boolean[], aligned accesses
+        testMatched(   Test::testZ_Z, Test::changeZ);
+        testMismatched(Test::testZ_B, Test::changeZ);
+        testMismatched(Test::testZ_S, Test::changeZ);
+        testMismatched(Test::testZ_C, Test::changeZ);
+        testMismatched(Test::testZ_I, Test::changeZ);
+        testMismatched(Test::testZ_J, Test::changeZ);
+        testMismatched(Test::testZ_F, Test::changeZ);
+        testMismatched(Test::testZ_D, Test::changeZ);
+
+        // byte[], aligned accesses
+        testMismatched(Test::testB_Z, Test::changeB);
+        testMatched(   Test::testB_B, Test::changeB);
+        testMismatched(Test::testB_S, Test::changeB);
+        testMismatched(Test::testB_C, Test::changeB);
+        testMismatched(Test::testB_I, Test::changeB);
+        testMismatched(Test::testB_J, Test::changeB);
+        testMismatched(Test::testB_F, Test::changeB);
+        testMismatched(Test::testB_D, Test::changeB);
+
+        // short[], aligned accesses
+        testMismatched(Test::testS_Z, Test::changeS);
+        testMismatched(Test::testS_B, Test::changeS);
+        testMatched(   Test::testS_S, Test::changeS);
+        testMismatched(Test::testS_C, Test::changeS);
+        testMismatched(Test::testS_I, Test::changeS);
+        testMismatched(Test::testS_J, Test::changeS);
+        testMismatched(Test::testS_F, Test::changeS);
+        testMismatched(Test::testS_D, Test::changeS);
+
+        // char[], aligned accesses
+        testMismatched(Test::testC_Z, Test::changeC);
+        testMismatched(Test::testC_B, Test::changeC);
+        testMismatched(Test::testC_S, Test::changeC);
+        testMatched(   Test::testC_C, Test::changeC);
+        testMismatched(Test::testC_I, Test::changeC);
+        testMismatched(Test::testC_J, Test::changeC);
+        testMismatched(Test::testC_F, Test::changeC);
+        testMismatched(Test::testC_D, Test::changeC);
+
+        // int[], aligned accesses
+        testMismatched(Test::testI_Z, Test::changeI);
+        testMismatched(Test::testI_B, Test::changeI);
+        testMismatched(Test::testI_S, Test::changeI);
+        testMismatched(Test::testI_C, Test::changeI);
+        testMatched(   Test::testI_I, Test::changeI);
+        testMismatched(Test::testI_J, Test::changeI);
+        testMismatched(Test::testI_F, Test::changeI);
+        testMismatched(Test::testI_D, Test::changeI);
+
+        // long[], aligned accesses
+        testMismatched(Test::testJ_Z, Test::changeJ);
+        testMismatched(Test::testJ_B, Test::changeJ);
+        testMismatched(Test::testJ_S, Test::changeJ);
+        testMismatched(Test::testJ_C, Test::changeJ);
+        testMismatched(Test::testJ_I, Test::changeJ);
+        testMatched(   Test::testJ_J, Test::changeJ);
+        testMismatched(Test::testJ_F, Test::changeJ);
+        testMismatched(Test::testJ_D, Test::changeJ);
+
+        // float[], aligned accesses
+        testMismatched(Test::testF_Z, Test::changeF);
+        testMismatched(Test::testF_B, Test::changeF);
+        testMismatched(Test::testF_S, Test::changeF);
+        testMismatched(Test::testF_C, Test::changeF);
+        testMismatched(Test::testF_I, Test::changeF);
+        testMismatched(Test::testF_J, Test::changeF);
+        testMatched(   Test::testF_F, Test::changeF);
+        testMismatched(Test::testF_D, Test::changeF);
+
+        // double[], aligned accesses
+        testMismatched(Test::testD_Z, Test::changeD);
+        testMismatched(Test::testD_B, Test::changeD);
+        testMismatched(Test::testD_S, Test::changeD);
+        testMismatched(Test::testD_C, Test::changeD);
+        testMismatched(Test::testD_I, Test::changeD);
+        testMismatched(Test::testD_J, Test::changeD);
+        testMismatched(Test::testD_F, Test::changeD);
+        testMatched(   Test::testD_D, Test::changeD);
+
+        // Object[], aligned accesses
+        testMismatched(Test::testL_Z, Test::changeL);
+        testMismatched(Test::testL_B, Test::changeL);
+        testMismatched(Test::testL_S, Test::changeL);
+        testMismatched(Test::testL_C, Test::changeL);
+        testMismatched(Test::testL_I, Test::changeL);
+        testMismatched(Test::testL_J, Test::changeL);
+        testMismatched(Test::testL_F, Test::changeL);
+        testMismatched(Test::testL_D, Test::changeL);
+        testMatched(   Test::testL_L, Test::changeL);
+
+        // Unaligned accesses
+        testMismatched(Test::testS_U, Test::changeS);
+        testMismatched(Test::testC_U, Test::changeC);
+        testMismatched(Test::testI_U, Test::changeI);
+        testMismatched(Test::testJ_U, Test::changeJ);
     }
 }