1/*
2 * Copyright (c) 2007, 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 6517249
27 * @summary JDWP: Cannot do an invokeMethod after a popFrames operation
28 * @author jjh
29 *
30 * @ignore 6951287
31 *
32 * @run build TestScaffold VMConnection TargetListener TargetAdapter
33 * @run compile -g PopAndInvokeTest.java
34 * @run driver PopAndInvokeTest
35 */
36import com.sun.jdi.*;
37import com.sun.jdi.event.*;
38import java.util.*;
39
40class PopAndInvokeTarg {
41    static boolean waiting = false;
42
43    public static void A() {
44        System.out.println("    debuggee: in A");
45    }
46
47    public static void invokeee() {
48        System.out.println("    debuggee: invokee");
49    }
50
51    public static void waiter() {
52        if (waiting) {
53            return;
54        }
55        waiting = true;
56        System.out.println("    debuggee: in waiter");
57        while (true) {
58        }
59    }
60
61    public static void main(String[] args) {
62        System.out.println("    debuggee: Howdy!");
63        /*
64         * Debugger will bkpt in A, popFrames back to here
65         * and then do an invokeMethod on invokeee.
66         * This should work.
67         */
68        A();
69
70        /*
71         * Debugger will resume and we will enter
72         * waiter().  Debugger will then do a suspend,
73         * a popFrames back to here, and an invoke
74         * which should fail.
75         */
76        waiter();
77        System.out.println("    debuggee: Goodbye from PopAndInvokeTarg!");
78    }
79}
80
81
82    /********** test program **********/
83
84public class PopAndInvokeTest extends TestScaffold {
85    ClassType targetClass;
86    ThreadReference mainThread;
87
88    PopAndInvokeTest (String args[]) {
89        super(args);
90    }
91
92    public static void main(String[] args)      throws Exception {
93        new PopAndInvokeTest(args).startTests();
94    }
95
96    StackFrame frameFor(String methodName) throws Exception {
97        Iterator it = mainThread.frames().iterator();
98
99        while (it.hasNext()) {
100            StackFrame frame = (StackFrame)it.next();
101            if (frame.location().method().name().equals(methodName)) {
102                return frame;
103            }
104        }
105        failure("FAIL: " + methodName + " not on stack");
106        return null;
107    }
108
109    /********** test core **********/
110
111    protected void runTests() throws Exception {
112        /*
113         * Get to the top of main()
114         * to determine targetClass and mainThread
115         */
116        runOnce();
117    }
118
119    void runOnce() throws Exception {
120
121        BreakpointEvent bpe = startTo("PopAndInvokeTarg", "A", "()V");
122        targetClass = (ClassType)bpe.location().declaringType();
123        mainThread = bpe.thread();
124
125        /*
126         * Verify that an invokeMethod works ok after a popFrames
127         * in a thread suspended by an event.
128         */
129        mainThread.popFrames(frameFor("A"));
130
131        System.out.println("Debugger: Popped back to the call to A()");
132        System.out.println("Debugger: Doing invoke");
133
134        Method invokeeeMethod = (Method)targetClass.methodsByName("invokeee").get(0);
135        try {
136            targetClass.invokeMethod(mainThread, invokeeeMethod,
137                                     new ArrayList(), 0);
138        } catch (Exception ex) {
139            failure("failure: invoke got unexpected exception: " + ex);
140            ex.printStackTrace();
141        }
142        System.out.println("Debugger: invoke done");
143
144        /*
145         * Verify that an invokeMethod gets an IncompatibleThreadStateException
146         * after a popFrames in a thread that is _not_ suspended by an event.
147         */
148        System.out.println("Debugger: Resuming debuggee");
149        vm().resume();
150
151        Field waiting = targetClass.fieldByName("waiting");
152        while (true) {
153            // Wait until debuggee enters the 'waiting' method.
154            BooleanValue bv= (BooleanValue)targetClass.getValue(waiting);
155            if (!bv.value()) {
156                try {
157                    Thread.sleep(10);
158                } catch (InterruptedException ee) {
159                }
160                continue;
161            }
162
163            // debuggee has entered the waiting method
164            System.out.println("Debugger: Suspending debuggee");
165            vm().suspend();
166            System.out.println("Debugger: Popping frame for waiter");
167            mainThread.popFrames(frameFor("waiter"));
168            System.out.println("Debugger: Invoking method");
169            try {
170                targetClass.invokeMethod(mainThread, invokeeeMethod,
171                                         new ArrayList(), 0);
172            } catch (IncompatibleThreadStateException ee) {
173                System.out.println("Debugger: Success: Got expected IncompatibleThreadStateException");
174                break;
175            } catch (Exception ee) {
176                failure("FAIL: Got unexpected exception: " + ee);
177                break;
178            }
179            failure("FAIL: Did not get IncompatibleThreadStateException " +
180                    "when debuggee is not suspended by an event");
181        }
182        listenUntilVMDisconnect();
183        if (testFailed) {
184            throw new Exception("PopAndInvokeTest failed");
185        }
186        System.out.println("Passed:");
187    }
188}
189