1 /* 2 * Copyright (c) 2019, 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 package runtime.valhalla.valuetypes; 24 25 import java.lang.ref.*; 26 27 28 /* 29 * @test Ifacmp 30 * @requires vm.gc == null 31 * @summary if_acmpeq/ne bytecode test 32 * @compile Ifacmp.java 33 * @run main/othervm -Xint -Xms16m -Xmx16m -XX:+UseSerialGC 34 * runtime.valhalla.valuetypes.Ifacmp 35 * @run main/othervm -Xcomp -Xms16m -Xmx16m -XX:+UseSerialGC 36 * runtime.valhalla.valuetypes.Ifacmp 37 */ 38 public class Ifacmp { 39 40 static inline class MyValue { 41 int value; 42 public MyValue(int v) { this.value = v; } 43 }; 44 static inline class MyValue2 { 45 int value; 46 public MyValue2(int v) { this.value = v; } 47 }; 48 49 boolean acmpModeInlineAlwaysFalse = false; 50 51 Object aNull = null; 52 Object bNull = null; 53 54 Object aObject = new String("Hi"); 55 Object bObject = new String("Hi"); 56 57 Object aValue = new MyValue(1); 58 Object bValue = new MyValue(1); 59 Object cValue = new MyValue(0); 60 Object aValue2 = new MyValue2(4711); 61 62 Object[][] equalUseCases = { 63 { aNull, bNull }, 64 { aObject, aObject }, 65 { aValue, bValue }, 66 { cValue, cValue }, 67 { aValue2, aValue2 } 68 }; 69 70 int objectEqualsUseCases = 2; // Nof object equals use cases 71 72 // Would just generate these fail case from the "equal set" above, 73 // but to do so needs ==, so write out by hand it is... 74 Object[][] notEqualUseCases = { 75 { aNull, aObject }, 76 { aNull, bObject }, 77 { aNull, aValue }, 78 { aNull, bValue }, 79 { aNull, cValue }, 80 { aNull, aValue2 }, 81 { aObject, bObject }, 82 { aObject, aValue }, 83 { aObject, bValue }, 84 { aObject, cValue }, 85 { aObject, aValue2 }, 86 { bObject, cValue }, 87 { bObject, aValue2 }, 88 { aValue, cValue }, 89 { aValue, aValue2 }, 90 }; 91 92 public Ifacmp() { this(false); } 93 public Ifacmp(boolean acmpModeInlineAlwaysFalse) { 94 this.acmpModeInlineAlwaysFalse = acmpModeInlineAlwaysFalse; 95 if (acmpModeInlineAlwaysFalse) { 96 System.out.println("ifacmp always false for inline types"); 97 } else { 98 System.out.println("ifacmp substitutability inline types"); 99 } 100 } 101 102 public void test() { 103 testAllUseCases(); 104 } 105 106 public void testUntilGc(int nofGc) { 107 for (int i = 0; i < nofGc; i++) { 108 System.out.println("GC num " + (i + 1)); 109 testUntilGc(); 110 } 111 } 112 113 public void testUntilGc() { 114 Reference ref = new WeakReference<Object>(new Object(), new ReferenceQueue<>()); 115 do { 116 test(); 117 } while (ref.get() != null); 118 } 119 120 public void testAllUseCases() { 121 int useCase = 0; 122 for (Object[] pair : equalUseCases) { 123 useCase++; 124 boolean equal = acmpModeInlineAlwaysFalse ? (useCase <= objectEqualsUseCases) : true; 125 checkEqual(pair[0], pair[1], equal); 126 } 127 for (Object[] pair : notEqualUseCases) { 128 checkEqual(pair[0], pair[1], false); 129 } 130 testLocalValues(); 131 } 132 133 public void testValues() { 134 checkEqual(aValue, bValue, true); 135 136 checkEqual(aValue, cValue, false); 137 checkEqual(aValue, aValue2, false); 138 checkEqual(aValue2, bValue, false); 139 checkEqual(aValue2, cValue, false); 140 testLocalValues(); 141 } 142 143 public void testLocalValues() { 144 // "aload + ifacmp" should be same as "aaload + ifamcp" 145 // but let's be paranoid... 146 MyValue a = new MyValue(11); 147 MyValue b = new MyValue(11); 148 MyValue c = a; 149 MyValue a1 = new MyValue(7); 150 MyValue2 a2 = new MyValue2(13); 151 152 if (acmpModeInlineAlwaysFalse) { 153 if (a == b) throw new RuntimeException("Always false fail " + a + " == " + b); 154 if (a == c) throw new RuntimeException("Always false fail " + a + " == " + c); 155 } else { 156 if (a != b) throw new RuntimeException("Substitutability test failed" + a + " != " + b); 157 if (a != c) throw new RuntimeException("Substitutability test failed"); 158 } 159 if (a == a1) throw new RuntimeException(); 160 checkEqual(a, a2, false); 161 } 162 163 boolean shouldEqualSelf(Object a) { 164 return acmpModeInlineAlwaysFalse ? (!(a != null && a.getClass().isInlineClass())) : true; 165 } 166 167 void checkEqual(Object a, Object b, boolean isEqual) { 168 testEquals(a, a, shouldEqualSelf(a)); 169 testEquals(b, b, shouldEqualSelf(b)); 170 testEquals(a, b, isEqual); 171 testNotEquals(a, b, !isEqual); 172 } 173 174 public static void testEquals(Object a, Object b, boolean expected) { 175 boolean isEqual = (a == b); 176 if (isEqual != expected) { 177 throw new RuntimeException("Expected " + expected + " : " 178 + a + " == " + b); 179 } 180 } 181 182 public static void testNotEquals(Object a, Object b, boolean expected) { 183 boolean isNotEqual = (a != b); 184 if (isNotEqual != expected) { 185 throw new RuntimeException("Expected " + expected + " : " 186 + a + " != " + b); 187 } 188 } 189 190 public static void main(String[] args) { 191 boolean inlineTypesAlwaysFalse = (args.length > 0) && args[0].equals("alwaysFalse"); 192 new Ifacmp(inlineTypesAlwaysFalse).test(); 193 new Ifacmp(inlineTypesAlwaysFalse).testUntilGc(3); 194 } 195 }