1 /*
2  * Copyright (c) 2009 SAP SE. 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
26  * @bug 6880034
27  * @summary SIGBUS during deoptimisation at a safepoint on 64bit-SPARC
28  *
29  * @run main/othervm -Xcomp -Xbatch
30  *    -XX:+PrintCompilation
31  *    -XX:CompileCommand=compileonly,compiler.c2.Test6880034::deopt_compiledframe_at_safepoint
32  *    compiler.c2.Test6880034
33  */
34 
35 package compiler.c2;
36 
37 // This test provokes a deoptimisation at a safepoint.
38 //
39 // It achieves this by compiling the method 'deopt_compiledframe_at_safepoint'
40 // before its first usage at a point in time when a call to the virtual method
41 // A::doSomething() from within 'deopt_compiledframe_at_safepoint' can be
42 // optimised to a static call because class A has no descendants.
43 //
44 // Later, when deopt_compiledframe_at_safepoint() is running, class B which
45 // extends A and overrides the virtual method "doSomething()", is loaded
46 // asynchronously in another thread.  This makes the compiled code of
47 // 'deopt_compiledframe_at_safepoint' invalid and triggers a deoptimisation of
48 // the frame where 'deopt_compiledframe_at_safepoint' is running in a
49 // loop.
50 //
51 // The deoptimisation leads to a SIGBUS on 64-bit server VMs on SPARC and to
52 // an incorrect result on 32-bit server VMs on SPARC due to a regression
53 // introduced by the change: "6420645: Create a vm that uses compressed oops
54 // for up to 32gb heapsizes"
55 // (http://hg.openjdk.java.net/jdk7/jdk7/hotspot/rev/ba764ed4b6f2).  Further
56 // investigation showed that change 6420645 is not really the root cause of
57 // this error but only reveals a problem with the float register encodings in
58 // sparc.ad which was hidden until now.
59 //
60 // Notice that for this test to fail in jtreg it is crucial that
61 // deopt_compiledframe_at_safepoint() runs in the main thread. Otherwise a
62 // crash in deopt_compiledframe_at_safepoint() will not be detected as a test
63 // failure by jtreg.
64 //
65 // Author: Volker H. Simonis
66 
67 public class Test6880034 {
68   static class A {
doSomething()69     public int doSomething() {
70       return 0;
71     }
72   }
73 
74   static class B extends A {
B()75     public B() {}
76     // override 'A::doSomething()'
doSomething()77     public int doSomething() {
78       return 1;
79     }
80   }
81 
82   static class G {
83     public static volatile A a = new A();
84 
85     // Change 'a' to point to a 'B' object
setAtoB()86     public static void setAtoB() {
87       try {
88         a =  (A) ClassLoader.
89                 getSystemClassLoader().
90                 loadClass("B").
91                 getConstructor(new Class[] {}).
92                 newInstance(new Object[] {});
93       }
94       catch (Exception e) {
95         System.out.println(e);
96       }
97     }
98   }
99 
100   public static volatile boolean is_in_loop = false;
101   public static volatile boolean stop_while_loop = false;
102 
deopt_compiledframe_at_safepoint()103   public static double deopt_compiledframe_at_safepoint() {
104     // This will be an optimised static call to A::doSomething() until we load "B"
105     int i = G.a.doSomething();
106 
107     // Need more than 16 'double' locals in this frame
108     double local1 = 1;
109     double local2 = 2;
110     double local3 = 3;
111     double local4 = 4;
112     double local5 = 5;
113     double local6 = 6;
114     double local7 = 7;
115     double local8 = 8;
116 
117     long k = 0;
118     // Once we load "B", this method will be made 'not entrant' and deoptimised
119     // at the safepoint which is at the end of this loop.
120     while (!stop_while_loop) {
121       if (k ==  1) local1 += i;
122       if (k ==  2) local2 += i;
123       if (k ==  3) local3 += i;
124       if (k ==  4) local4 += i;
125       if (k ==  5) local5 += i;
126       if (k ==  6) local6 += i;
127       if (k ==  7) local7 += i;
128       if (k ==  8) local8 += i;
129 
130       // Tell the world that we're now running wild in the loop
131       if (k++ == 20000) is_in_loop = true;
132     }
133 
134     return
135       local1 + local2 + local3 + local4 +
136       local5 + local6 + local7 + local8 + i;
137   }
138 
main(String[] args)139   public static void main(String[] args) {
140 
141     // Just to resolve G before we compile deopt_compiledframe_at_safepoint()
142     G g = new G();
143 
144     // Asynchronous thread which will eventually invalidate the code for
145     // deopt_compiledframe_at_safepoint() and therefore triggering a
146     // deoptimisation of that method.
147     new Thread() {
148       public void run() {
149         while (!is_in_loop) {
150           // Wait until the loop is running
151         }
152         // Load class 'B' asynchronously..
153         G.setAtoB();
154         // ..and stop the loop
155         stop_while_loop = true;
156       }
157     }.start();
158 
159     // Run the loop in deopt_compiledframe_at_safepoint()
160     double retVal = deopt_compiledframe_at_safepoint();
161 
162     System.out.println(retVal == 36 ? "OK" : "ERROR : " + retVal);
163     if (retVal != 36) throw new RuntimeException();
164   }
165 }
166