1 /*
2  * Copyright (c) 2001, 2015, 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
26  * @bug 4467564
27  * @summary Test the popping of frames in synchronous context
28  *          (that is, when stopped at an event)
29  * @author Robert Field
30  *
31  * @run build TestScaffold VMConnection TargetListener TargetAdapter
32  * @run compile -g PopSynchronousTest.java
33  * @run driver PopSynchronousTest
34  */
35 import com.sun.jdi.*;
36 import com.sun.jdi.event.*;
37 import com.sun.jdi.request.*;
38 
39 import java.util.*;
40 
41     /********** target program **********/
42 
43 class PopSynchronousTarg {
44     static String s;
45     static PopSynchronousTarg sole;
46 
a(int y, boolean w)47     synchronized void a(int y, boolean w) {
48         if (y == 6 && w) {
49             s += "@";
50         } else {
51             s += " aArgFail ";
52         }
53     }
b(String h)54     String b(String h) {
55         if (h.equals("yo")) {
56             s += "[";
57         } else {
58             s += " bArgFail ";
59         }
60         a(6, true);
61         s += "]";
62         return s;
63     }
c()64     long c() {
65         s += "<";
66         synchronized (s) {
67             b("yo");
68         }
69         s += ">";
70         return 17;
71     }
p()72     static void p() {
73         s += "(";
74         if (sole.c() != 17) {
75             s += " cReturnFail ";
76         }
77         s += ")";
78     }
report()79     static void report() {
80     }
main(String[] args)81     public static void main(String[] args){
82         s = new String();
83         sole = new PopSynchronousTarg();
84         for (int i = 0; i < 100; ++i) {
85             p();
86             // System.out.println(s);
87             report();
88         }
89     }
90 }
91 
92     /********** test program **********/
93 
94 public class PopSynchronousTest extends TestScaffold {
95     ReferenceType targetClass;
96     ThreadReference mainThread;
97     int stateIndex = 0;
98     String expected = "";
99     static final String[] calls =  {"a", "b", "c", "p", "main"};
100     static final int popMax = calls.length - 1;
101     static final String[] states =
102     {"main-i", "p-e", "p-i", "c-e", "c-i", "b-e", "b-i", "a-e", "a-l", "b-l", "c-l", "p-l", "main-r", "report-e"};
103     static final String[] output =
104     {"",       "",    "(",   "",    "<",   "",    "[",   "",    "@",   "]",   ">",   ")",   "",       ""};
105 
106 
PopSynchronousTest(String args[])107     PopSynchronousTest (String args[]) {
108         super(args);
109     }
110 
main(String[] args)111     public static void main(String[] args)      throws Exception {
112         new PopSynchronousTest(args).startTests();
113     }
114 
115 
116     /********** test assist **********/
117 
frameFor(String methodName)118     StackFrame frameFor(String methodName) throws Exception {
119         Iterator it = mainThread.frames().iterator();
120 
121         while (it.hasNext()) {
122             StackFrame frame = (StackFrame)it.next();
123             if (frame.location().method().name().equals(methodName)) {
124                 return frame;
125             }
126         }
127         failure("FAIL: " + methodName + " not on stack");
128         return null;
129     }
130 
actual()131     String actual() throws Exception {
132         Field field = targetClass.fieldByName("s");
133         StringReference sr = (StringReference)(targetClass.getValue(field));
134         return sr.value();
135     }
136 
checkExpected()137     void checkExpected() throws Exception {
138         if (!actual().equals(expected)) {
139             failure("FAIL: expected value: " + expected +
140                     " got: " + actual());
141         }
142     }
143 
methodIndex(String methodName)144     int methodIndex(String methodName) {
145         for (int i = 0; i < popMax; ++i) {
146             if (methodName.equals(calls[i])) {
147                 return i;
148             }
149         }
150         return -1;
151     }
152 
isTop(String methodName)153     boolean isTop(String methodName) throws Exception {
154         return mainThread.frame(0).location().method().name().equals(methodName);
155     }
156 
checkTop(String methodName, boolean atStart)157     void checkTop(String methodName, boolean atStart) throws Exception {
158         Location loc = mainThread.frame(0).location();
159         Method meth = loc.method();
160         String name = meth.name();
161         if (!isTop(methodName)) {
162             failure("FAIL: expected " + methodName +
163                     " at top of stack, instead: " + name);
164         } else if ((meth.location().codeIndex() == loc.codeIndex()) != atStart) {
165             failure("FAIL: not at expect position: " + loc.codeIndex());
166         }
167     }
168 
checkState()169     void checkState() throws Exception {
170         String name = states[stateIndex];
171         int dash = name.indexOf('-');
172         String methodName = name.substring(0,dash);
173         String posName = name.substring(dash+1);
174         checkTop(methodName, posName.equals("e"));
175         checkExpected();
176     }
177 
incrementState()178     void incrementState() {
179         stateIndex = (stateIndex + 1) % (states.length);
180     }
181 
resetState(String stateName)182     void resetState(String stateName) {
183         for (int i=0; i < states.length; ++i) {
184             if (states[i].equals(stateName)) {
185                 stateIndex = i;
186                 return;
187             }
188         }
189         failure("TEST FAILURE: cannot find state: " + stateName);
190     }
191 
resetExpected()192     void resetExpected() throws Exception {
193         println("Current value: " + actual());
194         Field field = targetClass.fieldByName("s");
195         expected = "";
196         ((ClassType)targetClass).setValue(field, vm().mirrorOf(expected));
197     }
198 
stateTo(String stateName)199     void stateTo(String stateName) {
200         do {
201             incrementState();
202             expected += output[stateIndex];
203         } while(!states[stateIndex].equals(stateName));
204     }
205 
resumeTo(String methodName)206     void resumeTo(String methodName) throws Exception {
207         List meths = targetClass.methodsByName(methodName);
208         Method meth = (Method)(meths.get(0));
209         resumeTo(meth.location());
210         stateTo(methodName + "-e");
211         checkState();
212     }
213 
pop(String methodName)214     void pop(String methodName) throws Exception {
215         mainThread.popFrames(frameFor(methodName));
216         resetState(methodName + "-e");
217         --stateIndex;
218         checkState();
219     }
220 
reenter(String methodName)221     void reenter(String methodName) throws Exception {
222         pop(methodName);
223         stepIntoInstruction(mainThread);
224         incrementState();
225         checkState();
226     }
227 
228     /********** test core **********/
229 
runTests()230     protected void runTests() throws Exception {
231         /*
232          * Get to the top of main()
233          * to determine targetClass and mainThread
234          */
235         BreakpointEvent bpe = startToMain("PopSynchronousTarg");
236         targetClass = bpe.location().declaringType();
237         mainThread = bpe.thread();
238 
239         /*
240          * Testing
241          */
242 
243         /* individual tests */
244         for (int i = 0; i < popMax; ++i) {
245             String from = calls[i];
246             for (int j = i; j < popMax; ++j) {
247                 String to = calls[j];
248                 String prev = calls[j+1];
249                 println("TEST pop from '" + from + "' to '" + to + "'");
250                 resumeTo(from);
251                 reenter(to);
252                 resumeTo("report");
253                 resetExpected();
254             }
255         }
256 
257         /* sequential tests */
258 
259         println("TEST pop a b c p");
260         resumeTo("a");
261         pop("a");
262         pop("b");
263         pop("c");
264         pop("p");
265         resumeTo("report");
266         resetExpected();
267 
268         println("TEST pop a c p");
269         resumeTo("a");
270         pop("a");
271         pop("c");
272         pop("p");
273         resumeTo("report");
274         resetExpected();
275 
276         println("TEST stress a");
277         resumeTo("a");
278         for (int i = 0; i < 100; ++i) {
279             reenter("a");
280         }
281         resumeTo("report");
282         resetExpected();
283 
284         println("TEST stress c");
285         resumeTo("c");
286         for (int i = 0; i < 100; ++i) {
287             reenter("c");
288         }
289         resumeTo("report");
290         resetExpected();
291 
292         /*
293          * we are done, get rid of target
294          */
295         vm().dispose();
296 
297         /*
298          * deal with results of test
299          * if anything has called failure("foo") testFailed will be true
300          */
301         if (!testFailed) {
302             println("PopSynchronousTest: passed");
303         } else {
304             throw new Exception("PopSynchronousTest: failed");
305         }
306     }
307 }
308