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  */
36 import com.sun.jdi.*;
37 import com.sun.jdi.event.*;
38 import java.util.*;
39 
40 class PopAndInvokeTarg {
41     static boolean waiting = false;
42 
A()43     public static void A() {
44         System.out.println("    debuggee: in A");
45     }
46 
invokeee()47     public static void invokeee() {
48         System.out.println("    debuggee: invokee");
49     }
50 
waiter()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 
main(String[] args)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 
84 public class PopAndInvokeTest extends TestScaffold {
85     ClassType targetClass;
86     ThreadReference mainThread;
87 
PopAndInvokeTest(String args[])88     PopAndInvokeTest (String args[]) {
89         super(args);
90     }
91 
main(String[] args)92     public static void main(String[] args)      throws Exception {
93         new PopAndInvokeTest(args).startTests();
94     }
95 
frameFor(String methodName)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 
runTests()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 
runOnce()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