1 /*
  2  * Copyright (c) 2024, 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 
 24 /*
 25  * @test id=Oops32
 26  * @requires vm.bits == 32 & vm.flagless
 27  * @library /test/lib
 28  * @modules java.base/jdk.internal.vm.annotation
 29  * @enablePreview
 30  * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
 31  * @run main/othervm FieldAlignmentTest 0
 32  */
 33 
 34   /*
 35  * @test id=CompressedOops
 36  * @requires vm.bits == 64 & vm.flagless
 37  * @library /test/lib
 38  * @modules java.base/jdk.internal.vm.annotation
 39  * @enablePreview
 40  * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
 41  * @run main/othervm FieldAlignmentTest 1
 42  */
 43 
 44   /*
 45  * @test id=NoCompressedOops
 46  * @requires vm.bits == 64 & vm.flagless
 47  * @library /test/lib
 48  * @modules java.base/jdk.internal.vm.annotation
 49  * @enablePreview
 50  * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
 51  * @run main/othervm FieldAlignmentTest 2
 52  */
 53 
 54  import java.util.ArrayList;
 55  import java.util.Collections;
 56  import java.util.List;
 57 
 58  import jdk.internal.vm.annotation.ImplicitlyConstructible;
 59 
 60  import jdk.test.lib.Asserts;
 61  import jdk.test.lib.ByteCodeLoader;
 62  import jdk.test.lib.helpers.ClassFileInstaller;
 63  import jdk.test.lib.compiler.InMemoryJavaCompiler;
 64  import jdk.test.lib.process.OutputAnalyzer;
 65  import jdk.test.lib.process.ProcessTools;
 66 
 67  public class FieldAlignmentTest {
 68   public static class ZeroByte { }
 69   public static class OneByte { byte b; }
 70   public static class TwoByte { byte b0; byte b1; }
 71   public static class ThreeByte { byte b0; byte b1; byte b2; }
 72   public static class FourByte { byte b0; byte b1; byte b2; byte b3; }
 73   public static class FiveByte { byte b0; byte b1; byte b2; byte b3; byte b4; }
 74   public static class SixByte { byte b0; byte b1; byte b2; byte b3; byte b4; byte b5; }
 75   public static class SevenByte { byte b0; byte b1; byte b2; byte b3; byte b4; byte b5; byte b6; }
 76   public static final String[] superNames = { ZeroByte.class.getCanonicalName(),
 77                                               OneByte.class.getCanonicalName(),
 78                                               TwoByte.class.getCanonicalName(),
 79                                               ThreeByte.class.getCanonicalName(),
 80                                               FourByte.class.getCanonicalName(),
 81                                               FiveByte.class.getCanonicalName(),
 82                                               SixByte.class.getCanonicalName(),
 83                                               SevenByte.class.getCanonicalName() };
 84   public static final String[] valueNames = { ValueOneByte.class.getCanonicalName(),
 85                                               ValueOneChar.class.getCanonicalName(),
 86                                               ValueOneShort.class.getCanonicalName(),
 87                                               ValueOneInt.class.getCanonicalName(),
 88                                               ValueOneLong.class.getCanonicalName(),
 89                                               ValueOneFloat.class.getCanonicalName(),
 90                                               ValueOneDouble.class.getCanonicalName(),
 91                                               ValueByteLong.class.getCanonicalName(),
 92                                               ValueByteInt.class.getCanonicalName() };
 93 
 94   List<String> testNames = new ArrayList<String>();
 95 
 96   @ImplicitlyConstructible static value class ValueOneByte { byte val = 0; }
 97   @ImplicitlyConstructible static value class ValueOneChar { char val = 0; }
 98   @ImplicitlyConstructible static value class ValueOneShort { short val = 0; }
 99   @ImplicitlyConstructible static value class ValueOneInt { int val = 0; }
100   @ImplicitlyConstructible static value class ValueOneLong { long val = 0; }
101   @ImplicitlyConstructible static value class ValueOneFloat { float val = 0f; }
102   @ImplicitlyConstructible static value class ValueOneDouble { double val = 0d; }
103 
104   @ImplicitlyConstructible static value class ValueByteLong { byte b = 0; long l = 0; }
105   @ImplicitlyConstructible static value class ValueByteInt { byte b = 0; int i = 0; }
106 
107   void generateTests() throws Exception {
108     for (String vName : valueNames) {
109       for (String sName : superNames) {
110         String vNameShort = vName.substring(vName.lastIndexOf('.') + 1);
111         String sNameShort = sName.substring(sName.lastIndexOf('.') + 1);
112         String className = "Test" + vNameShort + "With" + sNameShort;
113         String sourceCode = "import jdk.internal.vm.annotation.NullRestricted; " +
114                             "public class " + className + " extends " + sName + " { " +
115                             "    @NullRestricted" +
116                             "    " + vName + " v1;" +
117                             "}";
118         String java_version = System.getProperty("java.specification.version");
119         byte[] byteCode = InMemoryJavaCompiler.compile(className, sourceCode,
120                                                       "-source", java_version, "--enable-preview",
121                                                       "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED");
122         jdk.test.lib.helpers.ClassFileInstaller.writeClassToDisk(className, byteCode);
123         testNames.add(className);
124       }
125     }
126   }
127 
128   void generateTestRunner() throws Exception {
129     String className = "TestRunner";
130     StringBuilder sb = new StringBuilder();
131     sb.append("public class ").append(className).append(" {");
132     sb.append("    public void main(String[] args) {");
133     for (String name : testNames) {
134       sb.append("        ").append(name).append(" var").append(name).append(" = new ").append(name).append("();");
135     }
136     sb.append("    }");
137     sb.append("}");
138     String java_version = System.getProperty("java.specification.version");
139     byte[] byteCode = InMemoryJavaCompiler.compile(className, sb.toString(),
140                                                    "-source", java_version, "--enable-preview",
141                                                    "-cp", ".");
142     jdk.test.lib.helpers.ClassFileInstaller.writeClassToDisk(className, byteCode);
143   }
144 
145   static ProcessBuilder exec(String compressedOopsArg, String... args) throws Exception {
146     List<String> argsList = new ArrayList<>();
147     Collections.addAll(argsList, "--enable-preview");
148     Collections.addAll(argsList, "-XX:+UnlockDiagnosticVMOptions");
149     Collections.addAll(argsList, "-XX:+PrintFieldLayout");
150     Collections.addAll(argsList, "-Xshare:off");
151     if (compressedOopsArg != null) {
152       Collections.addAll(argsList, compressedOopsArg);
153     }
154     Collections.addAll(argsList, "-Xmx256m");
155     Collections.addAll(argsList, "-cp", System.getProperty("java.class.path") + ":.");
156     Collections.addAll(argsList, args);
157     return ProcessTools.createTestJavaProcessBuilder(argsList);
158   }
159 
160   public static void main(String[] args) throws Exception {
161     String compressedOopsArg;
162 
163     switch(args[0]) {
164       case "0": compressedOopsArg = null;
165                 break;
166       case "1": compressedOopsArg = "-XX:+UseCompressedOops";
167                 break;
168       case "2": compressedOopsArg = "-XX:-UseCompressedOops";
169                 break;
170       default: throw new RuntimeException("Unrecognized configuration");
171     }
172 
173     // Generate test classes
174     FieldAlignmentTest fat = new FieldAlignmentTest();
175     fat.generateTests();
176     fat.generateTestRunner();
177 
178     // Execute the test runner in charge of loading all test classes
179     ProcessBuilder pb = exec(compressedOopsArg, "TestRunner");
180     OutputAnalyzer out = new OutputAnalyzer(pb.start());
181 
182     // Analyze the test runner output
183     System.out.print(out.getOutput());
184     FieldLayoutAnalyzer.LogOutput lo = new FieldLayoutAnalyzer.LogOutput(out.asLines());
185 
186     FieldLayoutAnalyzer fla =  FieldLayoutAnalyzer.createFieldLayoutAnalyzer(lo);
187     fla.check();
188   }
189  }