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;
  52     private static int ADDRESS_SIZE;
  53     private static int HEADER_SIZE;
  54 
  55     static {
  56         // steal Unsafe
  57         try {
  58             Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
  59             unsafe.setAccessible(true);
  60             U = (Unsafe) unsafe.get(null);
  61         } catch (NoSuchFieldException | IllegalAccessException e) {
  62             throw new IllegalStateException(e);
  63         }
  64 
  65         // When running with CompressedOops on 64-bit platform, the address size
  66         // reported by Unsafe is still 8, while the real reference fields are 4 bytes long.
  67         // Try to guess the reference field size with this naive trick.
  68         try {
  69             long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1"));
  70             long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2"));
  71             ADDRESS_SIZE = (int) Math.abs(off2 - off1);
  72             HEADER_SIZE = (int) Math.min(off1, off2);
  73         } catch (NoSuchFieldException e) {
  74             ADDRESS_SIZE = -1;
  75         }
  76     }
  77 
  78     static class CompressedOopsClass {
  79         public Object obj1;
  80         public Object obj2;
  81     }
  82 
  83     public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception {
  84         Field f1 = klass.getDeclaredField(field1);
  85         Field f2 = klass.getDeclaredField(field2);
  86 
  87         if (isStatic(f1) != isStatic(f2)) {
  88             return true; // these guys are in naturally disjoint locations
  89         }
  90 
  91         int diff = offset(f1) - offset(f2);
  92         if (diff < 0) {
  93             // f1 is first
  94             return (offset(f2) - (offset(f1) + getSize(f1))) > 64;
  95         } else {
  96             // f2 is first
  97             return (offset(f1) - (offset(f2) + getSize(f2))) > 64;
  98         }
  99     }
 100 
 101     public static boolean isPadded(Class klass, String field1) throws Exception {
 102         Field f1 = klass.getDeclaredField(field1);
 103 
 104         if (isStatic(f1)) {
 105             return offset(f1) > 128 + 64;
 106         }
 107 
 108         return offset(f1) > 64;
 109     }
 110 
 111     public static boolean sameLayout(Class klass1, Class klass2) throws Exception {
 112         for (Field f1 : klass1.getDeclaredFields()) {
 113             Field f2 = klass2.getDeclaredField(f1.getName());
 114             if (offset(f1) != offset(f2)) {
 115                 return false;
 116             }
 117         }
 118 
 119         for (Field f2 : klass1.getDeclaredFields()) {
 120             Field f1 = klass2.getDeclaredField(f2.getName());
 121             if (offset(f1) != offset(f2)) {
 122                 return false;
 123             }
 124         }
 125 
 126         return true;
 127     }
 128 
 129     public static boolean isStatic(Field field) {
 130         return Modifier.isStatic(field.getModifiers());
 131     }
 132 
 133     public static int offset(Field field) {
 134         if (isStatic(field)) {
 135             return (int) U.staticFieldOffset(field);
 136         } else {
 137             return (int) U.objectFieldOffset(field);
 138         }
 139     }
 140 
 141     public static int getSize(Field field) {
 142         Class type = field.getType();
 143         if (type == byte.class)    { return 1; }
 144         if (type == boolean.class) { return 1; }
 145         if (type == short.class)   { return 2; }
 146         if (type == char.class)    { return 2; }
 147         if (type == int.class)     { return 4; }
 148         if (type == float.class)   { return 4; }
 149         if (type == long.class)    { return 8; }
 150         if (type == double.class)  { return 8; }
 151         return ADDRESS_SIZE;
 152     }
 153 
 154     public static void main(String[] args) throws Exception {
 155         boolean endResult = true;
 156 
 157         // --------------- INSTANCE FIELDS ---------------------
 158 
 159         if (arePaddedPairwise(Test1.class, "int1", "int2") ||
 160                 isPadded(Test1.class, "int1") ||
 161                 isPadded(Test1.class, "int2")) {
 162             System.err.println("Test1 failed");
 163             endResult &= false;
 164         }
 165 
 166         if (!arePaddedPairwise(Test2.class, "int1", "int2") ||
 167                 !isPadded(Test2.class, "int1") ||
 168                 isPadded(Test2.class, "int2")) {
 169             System.err.println("Test2 failed");
 170             endResult &= false;
 171         }
 172 
 173         if (!arePaddedPairwise(Test3.class, "int1", "int2") ||
 174                 !isPadded(Test3.class, "int1") ||
 175                 !isPadded(Test3.class, "int2")) {
 176             System.err.println("Test3 failed");
 177             endResult &= false;
 178         }
 179 
 180         if (arePaddedPairwise(Test4.class, "int1", "int2") ||
 181                 !isPadded(Test4.class, "int1") ||
 182                 !isPadded(Test4.class, "int2")) {
 183             System.err.println("Test4 failed");
 184             endResult &= false;
 185         }
 186 
 187         if (!arePaddedPairwise(Test5.class, "int1", "int2") ||
 188                 !isPadded(Test5.class, "int1") ||
 189                 !isPadded(Test5.class, "int2")) {
 190             System.err.println("Test5 failed");
 191             endResult &= false;
 192         }
 193 
 194         if (!arePaddedPairwise(Test6.class, "int1", "int2") ||
 195                 !isPadded(Test6.class, "int1") ||
 196                 !isPadded(Test6.class, "int2")) {
 197             System.err.println("Test6 failed");
 198             endResult &= false;
 199         }
 200 
 201         if (arePaddedPairwise(Test7.class, "int1", "int2") ||
 202                 !isPadded(Test7.class, "int1") ||
 203                 !isPadded(Test7.class, "int2")) {
 204             System.err.println("Test7 failed");
 205             endResult &= false;
 206         }
 207 
 208         if (!arePaddedPairwise(Test8.class, "int1", "int2") ||
 209                 !isPadded(Test8.class, "int1") ||
 210                 !isPadded(Test8.class, "int2")) {
 211             System.err.println("Test8 failed");
 212             endResult &= false;
 213         }
 214 
 215         if (!arePaddedPairwise(Test9.class, "int1", "int2") ||
 216                 !isPadded(Test9.class, "int1") ||
 217                 !isPadded(Test9.class, "int2")) {
 218             System.err.println("Test9 failed");
 219             endResult &= false;
 220         }
 221 
 222         if (!sameLayout(Test4.class, Test7.class)) {
 223             System.err.println("Test4 and Test7 have different layouts");
 224             endResult &= false;
 225         }
 226 
 227         if (!sameLayout(Test5.class, Test6.class)) {
 228             System.err.println("Test5 and Test6 have different layouts");
 229             endResult &= false;
 230         }
 231 
 232         if (!sameLayout(Test8.class, Test9.class)) {
 233             System.err.println("Test8 and Test9 have different layouts");
 234             endResult &= false;
 235         }
 236 
 237         System.out.println(endResult ? "Test PASSES" : "Test FAILS");
 238         if (!endResult) {
 239            throw new Error("Test failed");
 240         }
 241     }
 242 
 243     // ----------------------------------- INSTANCE FIELDS -----------------------------------------
 244 
 245     // naturally packed
 246     public static class Test1 {
 247                                  private int int1;
 248                                  private int int2;
 249     }
 250 
 251     // int1 is padded
 252     public static class Test2 {
 253         @Contended               private int int1;
 254                                  private int int2;
 255     }
 256 
 257     // both fields are padded
 258     public static class Test3 {
 259         @Contended               private int int1;
 260         @Contended               private int int2;
 261     }
 262 
 263     // fields are padded in the singular group
 264     public static class Test4 {
 265         @Contended("sameGroup")  private int int1;
 266         @Contended("sameGroup")  private int int2;
 267     }
 268 
 269     // fields are padded in disjoint groups
 270     public static class Test5 {
 271         @Contended("diffGroup1") private int int1;
 272         @Contended("diffGroup2") private int int2;
 273     }
 274 
 275     // fields are padded in disjoint groups
 276     public static class Test6 {
 277         @Contended               private int int1;
 278         @Contended("diffGroup2") private int int2;
 279     }
 280 
 281     // fields are padded in the singular group
 282     @Contended
 283     public static class Test7 {
 284                                  private int int1;
 285                                  private int int2;
 286     }
 287 
 288     // all fields are padded as the group, and one field is padded specifically
 289     @Contended
 290     public static class Test8 {
 291         @Contended               private int int1;
 292                                  private int int2;
 293     }
 294 
 295     // all fields are padded as the group, and one field is padded specifically
 296     @Contended
 297     public static class Test9 {
 298         @Contended("group")      private int int1;
 299                                  private int int2;
 300     }
 301 
 302 }
 303