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