1 /*
   2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.BufferedReader;
  25 import java.io.InputStreamReader;
  26 import java.lang.Class;
  27 import java.lang.String;
  28 import java.lang.System;
  29 import java.lang.management.ManagementFactory;
  30 import java.lang.management.RuntimeMXBean;
  31 import java.util.ArrayList;
  32 import java.util.List;
  33 import java.util.concurrent.CyclicBarrier;
  34 import java.util.regex.Matcher;
  35 import java.util.regex.Pattern;
  36 import java.lang.reflect.Field;
  37 import java.lang.reflect.Modifier;
  38 import jdk.internal.misc.Unsafe;
  39 import jdk.internal.vm.annotation.Contended;
  40 
  41 /*
  42  * @test
  43  * @bug     8003985
  44  * @summary Support Contended Annotation - JEP 142
  45  * @modules java.base/jdk.internal.misc
  46  * @modules java.base/jdk.internal.vm.annotation
  47  * @run main/othervm -XX:-RestrictContended Basic
  48  */
  49 public class Basic {
  50 
  51     private static final Unsafe U = Unsafe.getUnsafe();
  52     private static int ADDRESS_SIZE;
  53     private static int HEADER_SIZE;
  54 
  55     static {
  56         // When running with CompressedOops on 64-bit platform, the address size
  57         // reported by Unsafe is still 8, while the real reference fields are 4 bytes long.
  58         // Try to guess the reference field size with this naive trick.
  59         try {
  60             long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1"));
  61             long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2"));
  62             ADDRESS_SIZE = (int) Math.abs(off2 - off1);
  63             HEADER_SIZE = (int) Math.min(off1, off2);
  64         } catch (NoSuchFieldException e) {
  65             ADDRESS_SIZE = -1;
  66         }
  67     }
  68 
  69     static class CompressedOopsClass {
  70         public Object obj1;
  71         public Object obj2;
  72     }
  73 
  74     public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception {
  75         Field f1 = klass.getDeclaredField(field1);
  76         Field f2 = klass.getDeclaredField(field2);
  77 
  78         if (isStatic(f1) != isStatic(f2)) {
  79             return true; // these guys are in naturally disjoint locations
  80         }
  81 
  82         int diff = offset(f1) - offset(f2);
  83         if (diff < 0) {
  84             // f1 is first
  85             return (offset(f2) - (offset(f1) + getSize(f1))) > 64;
  86         } else {
  87             // f2 is first
  88             return (offset(f1) - (offset(f2) + getSize(f2))) > 64;
  89         }
  90     }
  91 
  92     public static boolean isPadded(Class klass, String field1) throws Exception {
  93         Field f1 = klass.getDeclaredField(field1);
  94 
  95         if (isStatic(f1)) {
  96             return offset(f1) > 128 + 64;
  97         }
  98 
  99         return offset(f1) > 64;
 100     }
 101 
 102     public static boolean sameLayout(Class klass1, Class klass2) throws Exception {
 103         for (Field f1 : klass1.getDeclaredFields()) {
 104             Field f2 = klass2.getDeclaredField(f1.getName());
 105             if (offset(f1) != offset(f2)) {
 106                 return false;
 107             }
 108         }
 109 
 110         for (Field f2 : klass1.getDeclaredFields()) {
 111             Field f1 = klass2.getDeclaredField(f2.getName());
 112             if (offset(f1) != offset(f2)) {
 113                 return false;
 114             }
 115         }
 116 
 117         return true;
 118     }
 119 
 120     public static boolean isStatic(Field field) {
 121         return Modifier.isStatic(field.getModifiers());
 122     }
 123 
 124     public static int offset(Field field) {
 125         if (isStatic(field)) {
 126             return (int) U.staticFieldOffset(field);
 127         } else {
 128             return (int) U.objectFieldOffset(field);
 129         }
 130     }
 131 
 132     public static int getSize(Field field) {
 133         Class type = field.getType();
 134         if (type == byte.class)    { return 1; }
 135         if (type == boolean.class) { return 1; }
 136         if (type == short.class)   { return 2; }
 137         if (type == char.class)    { return 2; }
 138         if (type == int.class)     { return 4; }
 139         if (type == float.class)   { return 4; }
 140         if (type == long.class)    { return 8; }
 141         if (type == double.class)  { return 8; }
 142         return ADDRESS_SIZE;
 143     }
 144 
 145     public static void main(String[] args) throws Exception {
 146         boolean endResult = true;
 147 
 148         // --------------- INSTANCE FIELDS ---------------------
 149 
 150         if (arePaddedPairwise(Test1.class, "int1", "int2") ||
 151                 isPadded(Test1.class, "int1") ||
 152                 isPadded(Test1.class, "int2")) {
 153             System.err.println("Test1 failed");
 154             endResult &= false;
 155         }
 156 
 157         if (!arePaddedPairwise(Test2.class, "int1", "int2") ||
 158                 !isPadded(Test2.class, "int1") ||
 159                 isPadded(Test2.class, "int2")) {
 160             System.err.println("Test2 failed");
 161             endResult &= false;
 162         }
 163 
 164         if (!arePaddedPairwise(Test3.class, "int1", "int2") ||
 165                 !isPadded(Test3.class, "int1") ||
 166                 !isPadded(Test3.class, "int2")) {
 167             System.err.println("Test3 failed");
 168             endResult &= false;
 169         }
 170 
 171         if (arePaddedPairwise(Test4.class, "int1", "int2") ||
 172                 !isPadded(Test4.class, "int1") ||
 173                 !isPadded(Test4.class, "int2")) {
 174             System.err.println("Test4 failed");
 175             endResult &= false;
 176         }
 177 
 178         if (!arePaddedPairwise(Test5.class, "int1", "int2") ||
 179                 !isPadded(Test5.class, "int1") ||
 180                 !isPadded(Test5.class, "int2")) {
 181             System.err.println("Test5 failed");
 182             endResult &= false;
 183         }
 184 
 185         if (!arePaddedPairwise(Test6.class, "int1", "int2") ||
 186                 !isPadded(Test6.class, "int1") ||
 187                 !isPadded(Test6.class, "int2")) {
 188             System.err.println("Test6 failed");
 189             endResult &= false;
 190         }
 191 
 192         if (arePaddedPairwise(Test7.class, "int1", "int2") ||
 193                 !isPadded(Test7.class, "int1") ||
 194                 !isPadded(Test7.class, "int2")) {
 195             System.err.println("Test7 failed");
 196             endResult &= false;
 197         }
 198 
 199         if (!arePaddedPairwise(Test8.class, "int1", "int2") ||
 200                 !isPadded(Test8.class, "int1") ||
 201                 !isPadded(Test8.class, "int2")) {
 202             System.err.println("Test8 failed");
 203             endResult &= false;
 204         }
 205 
 206         if (!arePaddedPairwise(Test9.class, "int1", "int2") ||
 207                 !isPadded(Test9.class, "int1") ||
 208                 !isPadded(Test9.class, "int2")) {
 209             System.err.println("Test9 failed");
 210             endResult &= false;
 211         }
 212 
 213         if (!sameLayout(Test4.class, Test7.class)) {
 214             System.err.println("Test4 and Test7 have different layouts");
 215             endResult &= false;
 216         }
 217 
 218         if (!sameLayout(Test5.class, Test6.class)) {
 219             System.err.println("Test5 and Test6 have different layouts");
 220             endResult &= false;
 221         }
 222 
 223         if (!sameLayout(Test8.class, Test9.class)) {
 224             System.err.println("Test8 and Test9 have different layouts");
 225             endResult &= false;
 226         }
 227 
 228         System.out.println(endResult ? "Test PASSES" : "Test FAILS");
 229         if (!endResult) {
 230            throw new Error("Test failed");
 231         }
 232     }
 233 
 234     // ----------------------------------- INSTANCE FIELDS -----------------------------------------
 235 
 236     // naturally packed
 237     public static class Test1 {
 238                                  private int int1;
 239                                  private int int2;
 240     }
 241 
 242     // int1 is padded
 243     public static class Test2 {
 244         @Contended               private int int1;
 245                                  private int int2;
 246     }
 247 
 248     // both fields are padded
 249     public static class Test3 {
 250         @Contended               private int int1;
 251         @Contended               private int int2;
 252     }
 253 
 254     // fields are padded in the singular group
 255     public static class Test4 {
 256         @Contended("sameGroup")  private int int1;
 257         @Contended("sameGroup")  private int int2;
 258     }
 259 
 260     // fields are padded in disjoint groups
 261     public static class Test5 {
 262         @Contended("diffGroup1") private int int1;
 263         @Contended("diffGroup2") private int int2;
 264     }
 265 
 266     // fields are padded in disjoint groups
 267     public static class Test6 {
 268         @Contended               private int int1;
 269         @Contended("diffGroup2") private int int2;
 270     }
 271 
 272     // fields are padded in the singular group
 273     @Contended
 274     public static class Test7 {
 275                                  private int int1;
 276                                  private int int2;
 277     }
 278 
 279     // all fields are padded as the group, and one field is padded specifically
 280     @Contended
 281     public static class Test8 {
 282         @Contended               private int int1;
 283                                  private int int2;
 284     }
 285 
 286     // all fields are padded as the group, and one field is padded specifically
 287     @Contended
 288     public static class Test9 {
 289         @Contended("group")      private int int1;
 290                                  private int int2;
 291     }
 292 
 293 }
 294