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 */
35import com.sun.jdi.*;
36import com.sun.jdi.event.*;
37import com.sun.jdi.request.*;
38
39import java.util.*;
40
41    /********** target program **********/
42
43class PopSynchronousTarg {
44    static String s;
45    static PopSynchronousTarg sole;
46
47    synchronized void a(int y, boolean w) {
48        if (y == 6 && w) {
49            s += "@";
50        } else {
51            s += " aArgFail ";
52        }
53    }
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    }
64    long c() {
65        s += "<";
66        synchronized (s) {
67            b("yo");
68        }
69        s += ">";
70        return 17;
71    }
72    static void p() {
73        s += "(";
74        if (sole.c() != 17) {
75            s += " cReturnFail ";
76        }
77        s += ")";
78    }
79    static void report() {
80    }
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
94public 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
107    PopSynchronousTest (String args[]) {
108        super(args);
109    }
110
111    public static void main(String[] args)      throws Exception {
112        new PopSynchronousTest(args).startTests();
113    }
114
115
116    /********** test assist **********/
117
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
131    String actual() throws Exception {
132        Field field = targetClass.fieldByName("s");
133        StringReference sr = (StringReference)(targetClass.getValue(field));
134        return sr.value();
135    }
136
137    void checkExpected() throws Exception {
138        if (!actual().equals(expected)) {
139            failure("FAIL: expected value: " + expected +
140                    " got: " + actual());
141        }
142    }
143
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
153    boolean isTop(String methodName) throws Exception {
154        return mainThread.frame(0).location().method().name().equals(methodName);
155    }
156
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
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
178    void incrementState() {
179        stateIndex = (stateIndex + 1) % (states.length);
180    }
181
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
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
199    void stateTo(String stateName) {
200        do {
201            incrementState();
202            expected += output[stateIndex];
203        } while(!states[stateIndex].equals(stateName));
204    }
205
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
214    void pop(String methodName) throws Exception {
215        mainThread.popFrames(frameFor(methodName));
216        resetState(methodName + "-e");
217        --stateIndex;
218        checkState();
219    }
220
221    void reenter(String methodName) throws Exception {
222        pop(methodName);
223        stepIntoInstruction(mainThread);
224        incrementState();
225        checkState();
226    }
227
228    /********** test core **********/
229
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