1 /* 2 * Copyright (c) 2019, 2024, 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.inlinetypes; 24 25 import jdk.test.lib.Asserts; 26 27 import java.lang.reflect.Field; 28 29 import jdk.internal.value.ValueClass; 30 import jdk.internal.vm.annotation.ImplicitlyConstructible; 31 import jdk.internal.vm.annotation.LooselyConsistentValue; 32 import jdk.internal.vm.annotation.NullRestricted; 33 34 35 /* 36 * @test 37 * @summary Test support for empty inline types (no instance fields) 38 * @library /test/lib 39 * @modules java.base/jdk.internal.vm.annotation 40 * java.base/jdk.internal.value 41 * @enablePreview 42 * @compile EmptyInlineTest.java 43 * @run main/othervm -XX:InlineFieldMaxFlatSize=128 runtime.valhalla.inlinetypes.EmptyInlineTest 44 */ 45 46 public class EmptyInlineTest { 47 48 @ImplicitlyConstructible 49 @LooselyConsistentValue 50 static value class EmptyInline { 51 public boolean isEmpty() { 52 return true; 53 } 54 } 55 56 @ImplicitlyConstructible 57 @LooselyConsistentValue 58 static value class EmptyField { 59 @NullRestricted 60 EmptyInline empty; 61 62 EmptyField() { 63 this.empty = new EmptyInline(); 64 } 65 } 66 67 static class WithInt { 68 int i; 69 } 70 71 static class WithEmptyField extends WithInt { 72 // With current layout strategy for reference classs, the empty 73 // inline field would be placed between the int and the Object 74 // fields, along with some padding. 75 Object o; 76 @NullRestricted 77 EmptyInline empty; 78 } 79 80 public static void main(String[] args) { 81 // Create an empty inline 82 EmptyInline empty = new EmptyInline(); 83 Asserts.assertTrue(empty.isEmpty()); 84 85 // Create an inline with an empty inline field 86 EmptyField emptyField = new EmptyField(); 87 Asserts.assertEquals(emptyField.empty.getClass(), EmptyInline.class); 88 Asserts.assertTrue(emptyField.empty.isEmpty()); 89 System.out.println(emptyField.empty.isEmpty()); 90 91 // Regular instance with an empty field inside 92 WithEmptyField w = new WithEmptyField(); 93 Asserts.assertEquals(w.empty.getClass(), EmptyInline.class); 94 Asserts.assertTrue(w.empty.isEmpty()); 95 w.empty = new EmptyInline(); 96 Asserts.assertEquals(w.empty.getClass(), EmptyInline.class); 97 Asserts.assertTrue(w.empty.isEmpty()); 98 99 // Create an array of empty inlines 100 EmptyInline[] emptyArray = (EmptyInline[])ValueClass.newNullRestrictedArray(EmptyInline.class, 100); 101 for(EmptyInline element : emptyArray) { 102 Asserts.assertEquals(element.getClass(), EmptyInline.class); 103 Asserts.assertTrue(element.isEmpty()); 104 } 105 106 // Testing arrayCopy 107 EmptyInline[] array2 = (EmptyInline[])ValueClass.newNullRestrictedArray(EmptyInline.class, 100); 108 // with two arrays 109 System.arraycopy(emptyArray, 10, array2, 20, 50); 110 for(EmptyInline element : array2) { 111 Asserts.assertEquals(element.getClass(), EmptyInline.class); 112 Asserts.assertTrue(element.isEmpty()); 113 } 114 // single array, no overlap 115 System.arraycopy(emptyArray, 10, emptyArray, 50, 20); 116 for(EmptyInline element : emptyArray) { 117 Asserts.assertEquals(element.getClass(), EmptyInline.class); 118 Asserts.assertTrue(element.isEmpty()); 119 } 120 // single array with overlap 121 System.arraycopy(emptyArray, 10, emptyArray, 20, 50); 122 for(EmptyInline element : emptyArray) { 123 Asserts.assertEquals(element.getClass(), EmptyInline.class); 124 Asserts.assertTrue(element.isEmpty()); 125 } 126 127 // Passing an empty inline in argument 128 assert isEmpty(empty); 129 130 // Returning an empty inline 131 assert getEmpty().isEmpty(); 132 133 // Checking fields with reflection 134 Class<?> c = empty.getClass(); 135 try { 136 Field[] fields = c.getDeclaredFields(); 137 Asserts.assertTrue(fields.length == 0); 138 } catch (Throwable t) { 139 t.printStackTrace(); 140 throw t; 141 } 142 WithEmptyField w0 = new WithEmptyField(); 143 Class<?> c2 = w0.getClass(); 144 try { 145 Field emptyfield = c2.getDeclaredField("empty"); 146 EmptyInline e = (EmptyInline)emptyfield.get(w0); 147 Asserts.assertEquals(e.getClass(), EmptyInline.class); 148 Asserts.assertTrue(e.isEmpty()); 149 emptyfield.set(w0, new EmptyInline()); 150 e = (EmptyInline)emptyfield.get(w0); 151 Asserts.assertEquals(e.getClass(), EmptyInline.class); 152 Asserts.assertTrue(e.isEmpty()); 153 } catch(Throwable t) { 154 t.printStackTrace(); 155 throw new RuntimeException("Reflection tests failed: " + t); 156 } 157 158 // Testing JIT compiler 159 // for(int i=0; i < 100000; i++) { 160 // test(); 161 // } 162 } 163 164 static boolean isEmpty(EmptyInline empty) { 165 return empty.isEmpty(); 166 } 167 168 static EmptyInline getEmpty() { 169 return new EmptyInline(); 170 } 171 172 static void test() { 173 for(int i=0; i < 10000; i++) { 174 Asserts.assertTrue(getEmpty().isEmpty()); 175 } 176 } 177 }