86783b9851
Co-authored-by: Gui Cao <gcao@openjdk.org> Co-authored-by: Dingli Zhang <dzhang@openjdk.org> Co-authored-by: Martin Doerr <mdoerr@openjdk.org> Reviewed-by: coleenp, fparain
236 lines
9.7 KiB
Java
236 lines
9.7 KiB
Java
/*
|
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8309808 8309811
|
|
* @summary Test the output of the HotSpot BytecodeTracer and ClassPrinter classes.
|
|
* @library /test/lib
|
|
* @build jdk.test.whitebox.WhiteBox Linked2 Unlinked2
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI BytecodeTracerTest
|
|
*/
|
|
|
|
import java.io.BufferedWriter;
|
|
import java.io.FileWriter;
|
|
import java.lang.invoke.MethodHandle;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import jdk.test.lib.Asserts;
|
|
import jdk.test.whitebox.WhiteBox;
|
|
|
|
public class BytecodeTracerTest {
|
|
private final static String Linked_className = Linked.class.getName();
|
|
private final static String Linked2_className = Linked2.class.getName();
|
|
|
|
// This loads the "Unlinked" and "Unlinked2" classes, but doesn't link them.
|
|
private final static String Unlinked_className = Unlinked.class.getName();
|
|
private final static String Unlinked2_className = Unlinked2.class.getName();
|
|
|
|
public static void staticMethod() { }
|
|
public void virtualMethod() { }
|
|
int x;
|
|
static long y;
|
|
|
|
public static class Linked {
|
|
public static void doit(String args[]) {
|
|
System.out.println("num args = " + args.length);
|
|
}
|
|
public String test_ldc() {
|
|
Class c = Unloaded.class;
|
|
return "Literal\u5678";
|
|
}
|
|
public void test_invoke(BytecodeTracerTest obj) {
|
|
obj.virtualMethod();
|
|
staticMethod();
|
|
}
|
|
public void test_field(BytecodeTracerTest obj) {
|
|
y = obj.x;
|
|
}
|
|
public void test_invokehandle(MethodHandle mh) throws Throwable {
|
|
mh.invokeExact(4.0f, "String", this);
|
|
}
|
|
}
|
|
|
|
public static class Unlinked {
|
|
public String toString() {
|
|
return "Unlinked" + this.hashCode();
|
|
}
|
|
public String test_ldc() {
|
|
Class c = Unloaded.class;
|
|
return "Literal\u1234";
|
|
}
|
|
public void test_invoke(BytecodeTracerTest obj) {
|
|
obj.virtualMethod();
|
|
staticMethod();
|
|
}
|
|
public void test_field(BytecodeTracerTest obj) {
|
|
y = obj.x;
|
|
}
|
|
public void test_invokehandle(MethodHandle mh) throws Throwable {
|
|
mh.invokeExact(4.0f, "String", this);
|
|
}
|
|
}
|
|
|
|
// This class is never loaded during the execution of BytecodeTracerTest
|
|
public static class Unloaded { }
|
|
|
|
static int testCount = 0;
|
|
String testNote;
|
|
String output;
|
|
|
|
BytecodeTracerTest(String note) {
|
|
++ testCount;
|
|
testNote = "======================================================================\nTest case "
|
|
+ testCount + ": " + note + "\n ";
|
|
}
|
|
|
|
void logOutput() throws Exception {
|
|
String logFileName = "log-" + testCount + ".txt";
|
|
System.out.println("Output saved in " + logFileName);
|
|
BufferedWriter writer = new BufferedWriter(new FileWriter(logFileName));
|
|
writer.write(output);
|
|
writer.close();
|
|
}
|
|
|
|
BytecodeTracerTest printClasses(String classNamePattern, int flags) throws Exception {
|
|
System.out.println(testNote + "printClasses(\"" + classNamePattern + "\", " + flags + ")");
|
|
output = WhiteBox.getWhiteBox().printClasses(classNamePattern, flags);
|
|
logOutput();
|
|
return this;
|
|
}
|
|
|
|
BytecodeTracerTest printMethods(String classNamePattern, String methodPattern, int flags) throws Exception {
|
|
System.out.println(testNote + "printMethods(\"" + classNamePattern + "\", \"" + methodPattern + "\", " + flags + ")");
|
|
output = WhiteBox.getWhiteBox().printMethods(classNamePattern, methodPattern, flags);
|
|
logOutput();
|
|
return this;
|
|
}
|
|
|
|
BytecodeTracerTest printLinkedMethods(String methodPattern) throws Exception {
|
|
return printMethods(Linked_className, methodPattern, 0xff);
|
|
}
|
|
|
|
BytecodeTracerTest printLinked2Methods(String methodPattern) throws Exception {
|
|
return printMethods(Linked2_className, methodPattern, 0xff);
|
|
}
|
|
|
|
BytecodeTracerTest printUnlinkedMethods(String methodPattern) throws Exception {
|
|
return printMethods(Unlinked_className, methodPattern, 0xff);
|
|
}
|
|
|
|
BytecodeTracerTest printUnlinked2Methods(String methodPattern) throws Exception {
|
|
return printMethods(Unlinked2_className, methodPattern, 0xff);
|
|
}
|
|
|
|
BytecodeTracerTest mustMatch(String pattern) {
|
|
Pattern p = Pattern.compile(pattern, Pattern.MULTILINE);
|
|
Matcher m = p.matcher(output);
|
|
boolean found = m.find();
|
|
if (!found) {
|
|
System.err.println("********* output ********");
|
|
System.err.println(output);
|
|
System.err.println("*************************");
|
|
}
|
|
Asserts.assertTrue(found,
|
|
"Missing pattern: \"" + pattern + "\"");
|
|
System.out.println("Found pattern: " + pattern);
|
|
System.out.println(" ==>: " + m.group());
|
|
return this;
|
|
}
|
|
|
|
static BytecodeTracerTest test(String note) {
|
|
return new BytecodeTracerTest(note);
|
|
}
|
|
|
|
public static void main(String args[]) throws Exception {
|
|
// Force "Linked" and "Linked2" classes to be linked (and rewritten);
|
|
Linked.doit(args);
|
|
Asserts.assertTrue(Linked2.test_ldc() == 12345, "must be");
|
|
|
|
test("invokedynamic in linked class")
|
|
.printClasses("BytecodeTracerTest$Linked", 0xff)
|
|
.mustMatch("invokedynamic bsm=[0-9]+ [0-9]+ <makeConcatWithConstants[(]I[)]Ljava/lang/String;>")
|
|
.mustMatch("BSM: REF_invokeStatic [0-9]+ <java/lang/invoke/StringConcatFactory.makeConcatWithConstants[(]")
|
|
.mustMatch("\"num args = [\\\\]u0001\"") // static param for string concat
|
|
.mustMatch(".*getstatic [0-9]+ <java/lang/System.out:Ljava/io/PrintStream;>");
|
|
|
|
test("invokedynamic in unlinked class")
|
|
.printUnlinkedMethods("toString")
|
|
.mustMatch("invokedynamic bsm=[0-9]+ [0-9]+ <makeConcatWithConstants[(]I[)]Ljava/lang/String;>");
|
|
|
|
test("ldc in linked class")
|
|
.printLinkedMethods("test_ldc")
|
|
.mustMatch("ldc BytecodeTracerTest[$]Unloaded")
|
|
.mustMatch("fast_aldc \"Literal[\\\\]u5678\""); // ldc of String has been rewritten during linking
|
|
|
|
test("ldc in unlinked class")
|
|
.printUnlinkedMethods("test_ldc")
|
|
.mustMatch(" ldc BytecodeTracerTest[$]Unloaded")
|
|
.mustMatch(" ldc \"Literal[\\\\]u1234\""); // ldc of String is not rewritten
|
|
|
|
test("More ldc tests in linked class")
|
|
.printLinked2Methods("test_ldc")
|
|
.mustMatch("ldc_w 2")
|
|
.mustMatch("fast_aldc_w \"Hello\"")
|
|
.mustMatch("BSM: REF_invokeStatic [0-9]+ <Linked2.condyBSM[(]Ljava/lang/invoke/MethodHandles")
|
|
.mustMatch("fast_aldc <MethodHandle of kind [0-9]+ index at [0-9]+> [0-9]+ <Linked2.test_ldc[(][)]I>");
|
|
|
|
test("More ldc tests in unlinked class")
|
|
.printUnlinked2Methods("test_ldc")
|
|
.mustMatch("ldc_w 2")
|
|
.mustMatch("ldc_w \"Hello\"")
|
|
.mustMatch("BSM: REF_invokeStatic [0-9]+ <Unlinked2.condyBSM[(]Ljava/lang/invoke/MethodHandles")
|
|
.mustMatch("ldc <MethodHandle of kind [0-9]+ index at [0-9]+> [0-9]+ <Unlinked2.test_ldc[(][)]I>");
|
|
|
|
test("plain old invoke in linked class")
|
|
.printLinkedMethods("test_invoke")
|
|
.mustMatch("invokevirtual [0-9]+ <BytecodeTracerTest.virtualMethod[(][)]V>")
|
|
.mustMatch("invokestatic [0-9]+ <BytecodeTracerTest.staticMethod[(][)]V>");
|
|
|
|
test("plain old invoke in unlinked class")
|
|
.printUnlinkedMethods("test_invoke")
|
|
.mustMatch("invokevirtual [0-9]+ <BytecodeTracerTest.virtualMethod[(][)]V>")
|
|
.mustMatch("invokestatic [0-9]+ <BytecodeTracerTest.staticMethod[(][)]V>");
|
|
|
|
test("invokehandle in linked class")
|
|
.printLinkedMethods("test_invokehandle")
|
|
.mustMatch("invokehandle [0-9]+ <java/lang/invoke/MethodHandle.invokeExact[(]FLjava/lang/String;LBytecodeTracerTest[$]Linked;[)]V>");
|
|
|
|
test("invokehandle in unlinked class")
|
|
.printUnlinkedMethods("test_invokehandle")
|
|
.mustMatch("invokevirtual [0-9]+ <java/lang/invoke/MethodHandle.invokeExact[(]FLjava/lang/String;LBytecodeTracerTest[$]Unlinked;[)]V>");
|
|
|
|
test("field in linked class")
|
|
.printLinkedMethods("test_field")
|
|
.mustMatch("getfield [0-9]+ <BytecodeTracerTest.x:I>")
|
|
.mustMatch("putstatic [0-9]+ <BytecodeTracerTest.y:J>");
|
|
|
|
test("field in unlinked class")
|
|
.printUnlinkedMethods("test_field")
|
|
.mustMatch("getfield [0-9]+ <BytecodeTracerTest.x:I>")
|
|
.mustMatch("putstatic [0-9]+ <BytecodeTracerTest.y:J>");
|
|
}
|
|
}
|
|
|