1+ /*
2+ * Copyright (c) 2023, 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+ import jdk .test .lib .process .OutputAnalyzer ;
26+ import jdk .test .lib .process .ProcessTools ;
27+ import jdk .test .lib .Utils ;
28+ import java .util .ArrayList ;
29+ import java .util .Arrays ;
30+ import java .util .List ;
31+
32+ /*
33+ * @test StackWalkNativeToJava
34+ * @bug 8316309
35+ * @summary Check that walking the stack works fine when going from C++ frame to Java frame.
36+ * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
37+ * @requires os.family != "windows"
38+ * @requires vm.flagless
39+ * @library /test/lib
40+ * @run driver StackWalkNativeToJava
41+ */
42+
43+ public class StackWalkNativeToJava {
44+
45+ public static void main (String [] args ) throws Exception {
46+ // Check stack walking works fine when sender of C++ frame
47+ // is a Java native method.
48+ testStackWalkNativeToJavaNative ("-Xint" );
49+ testStackWalkNativeToJavaNative ("-Xcomp" , "-XX:CompileCommand=dontinline,StackWalkNativeToJava$TestNativeToJavaNative::*" );
50+
51+ // Check stack walking works fine when sender of C++ frame
52+ // is a runtime stub or interpreted Java method (VM call from Java).
53+ testStackWalkNativeToJava ("-Xint" );
54+ testStackWalkNativeToJava ("-Xcomp" , "-XX:TieredStopAtLevel=3" ,
55+ "-XX:CompileCommand=dontinline,StackWalkNativeToJava$TestNativeToJava::*" );
56+ }
57+
58+ public static void testStackWalkNativeToJavaNative (String ... extraFlags ) throws Exception {
59+ List <String > commands = new ArrayList <>();
60+ commands .add ("-Xbootclasspath/a:." );
61+ commands .add ("-XX:-CreateCoredumpOnCrash" );
62+ commands .add ("-XX:+UnlockDiagnosticVMOptions" );
63+ commands .add ("-XX:AbortVMOnException=java.lang.IllegalMonitorStateException" );
64+ commands .add ("-XX:+ErrorFileToStdout" );
65+ commands .addAll (Arrays .asList (extraFlags ));
66+ commands .add ("StackWalkNativeToJava$TestNativeToJavaNative" );
67+
68+ ProcessBuilder pb = ProcessTools .createJavaProcessBuilder (commands );
69+ OutputAnalyzer output = new OutputAnalyzer (pb .start ());
70+ output .shouldNotContain ("java.lang.RuntimeException: Reached statement after obj.wait()" );
71+ output .shouldNotContain ("[error occurred during error reporting (printing native stack" );
72+ String [] res = output .getOutput ().split ("StackWalkNativeToJava\\ $TestNativeToJavaNative\\ .callNativeMethod\\ (\\ )V" );
73+ assertTrue (res .length - 1 == 2 , res .length - 1 );
74+ output .shouldNotHaveExitValue (0 );
75+ }
76+
77+ public static class TestNativeToJavaNative {
78+ public static void main (String [] args ) throws Exception {
79+ TestNativeToJavaNative test = new TestNativeToJavaNative ();
80+ test .callNativeMethod ();
81+ }
82+
83+ public void callNativeMethod () throws Exception {
84+ Object obj = new Object ();
85+ // Trigger a fatal exit due to IllegalMonitorStateException during
86+ // a call to the VM from a Java native method.
87+ obj .wait ();
88+ throw new RuntimeException ("Reached statement after obj.wait()" );
89+ }
90+ }
91+
92+ public static void testStackWalkNativeToJava (String ... extraFlags ) throws Exception {
93+ List <String > commands = new ArrayList <>();
94+ commands .add ("-Xbootclasspath/a:." );
95+ commands .add ("-XX:-CreateCoredumpOnCrash" );
96+ commands .add ("-XX:+UnlockDiagnosticVMOptions" );
97+ commands .add ("-XX:DiagnoseSyncOnValueBasedClasses=1" );
98+ commands .add ("-XX:+ErrorFileToStdout" );
99+ commands .addAll (Arrays .asList (extraFlags ));
100+ commands .add ("StackWalkNativeToJava$TestNativeToJava" );
101+
102+ ProcessBuilder pb = ProcessTools .createJavaProcessBuilder (commands );
103+ OutputAnalyzer output = new OutputAnalyzer (pb .start ());
104+ output .shouldNotContain ("java.lang.RuntimeException: Reached statement after synchronized" );
105+ output .shouldNotContain ("[error occurred during error reporting (printing native stack" );
106+ String [] res = output .getOutput ().split ("StackWalkNativeToJava\\ $TestNativeToJava\\ .callVMMethod\\ (\\ )V" );
107+ assertTrue (res .length - 1 == 2 , res .length - 1 );
108+ output .shouldNotHaveExitValue (0 );
109+ }
110+
111+ public static class TestNativeToJava {
112+ static Integer counter = 0 ;
113+
114+ public static void main (String [] args ) throws Exception {
115+ TestNativeToJava test = new TestNativeToJava ();
116+ test .callVMMethod ();
117+ }
118+
119+ public void callVMMethod () throws Exception {
120+ // Trigger a fatal exit for trying to synchronize on a value based class
121+ // during a call to the VM from a Java method.
122+ synchronized (counter ) {
123+ counter ++;
124+ }
125+ throw new RuntimeException ("Reached statement after synchronized" );
126+ }
127+ }
128+
129+ private static void assertTrue (boolean condition , int count ) {
130+ if (!condition ) {
131+ throw new RuntimeException ("Count error: count was " + count );
132+ }
133+ }
134+ }
0 commit comments