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 
  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 
  84 public 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 }