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