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