1 /*
   2  * Copyright (c) 2001, 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 4409241 4432820
  27  * @summary Test the bug fix for: MethodExitEvents disappear when Object-Methods are called from main
  28  * @author Tim Bell
  29  *
  30  * @run build TestScaffold VMConnection TargetListener TargetAdapter
  31  * @run compile -g MethodEntryExitEvents.java
  32  * @run driver MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee
  33  * @run driver MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee
  34  * @run driver MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee
  35  */
  36 import com.sun.jdi.*;
  37 import com.sun.jdi.event.*;
  38 import com.sun.jdi.request.*;
  39 import java.util.*;
  40 
  41 class t2 {
  42     public static void sayHello1(int i, int j) {
  43         sayHello2(i, j);
  44     }
  45     public static void sayHello2(int i, int j) {
  46         sayHello3(i, j);
  47     }
  48     public static void sayHello3(int i, int j) {
  49         sayHello4(i, j);
  50     }
  51     public static void sayHello4(int i, int j) {
  52         sayHello5(i, j);
  53     }
  54     public static void sayHello5(int i, int j) {
  55         if (i < 2) {
  56             sayHello1(++i, j);
  57         } else {
  58             System.out.print  ("MethodEntryExitEventsDebugee: ");
  59             System.out.print  ("    -->> Hello.  j is: ");
  60             System.out.print  (j);
  61             System.out.println(" <<--");
  62         }
  63     }
  64 }
  65 
  66 class MethodEntryExitEventsDebugee {
  67     public static void loopComplete () {
  68         /*
  69          * The implementation here is deliberately inefficient
  70          * because the debugger is still watching this method.
  71          */
  72         StringBuffer sb = new StringBuffer();
  73         sb.append ("MethodEntryExitEventsDebugee: ");
  74         sb.append ("Executing loopComplete method for a graceful shutdown...");
  75         String s = sb.toString();
  76         for (int i = 0; i < s.length(); i++) {
  77             char c = s.charAt(i);
  78             System.out.print(c);
  79         }
  80         System.out.println();
  81     }
  82     public static void main(String[] args) {
  83         t2 test = new t2();
  84         for (int j = 0; j < 3; j++) {
  85             test.sayHello1(0, j);
  86         }
  87         loopComplete();
  88     }
  89 }
  90 
  91 
  92 public class MethodEntryExitEvents extends TestScaffold {
  93     int sessionSuspendPolicy = EventRequest.SUSPEND_ALL;
  94     StepRequest stepReq = null; //Only one step request allowed per thread
  95     boolean finishedCounting = false;
  96 
  97     /*
  98      * Enter main() , then t2.<init>, then sayHello[1,2,3,4,5] 15 times 3 loops,
  99      * then loopComplete()
 100      */
 101     final int expectedEntryCount = 1 + 1 + (15 * 3) + 1;
 102     int methodEntryCount = 0;
 103 
 104     /*
 105      * Exit t2.<init>, then sayHello[1,2,3,4,5] 15 times 3 loopa
 106      * (event monitoring is cancelled before we exit loopComplete() or main())
 107      */
 108     final int expectedExitCount = 1 + (15 * 3);
 109     int methodExitCount = 0;
 110 
 111     // Classes which we are interested in
 112     private List includes = Arrays.asList(new String[] {
 113         "MethodEntryExitEventsDebugee",
 114         "t2"
 115     });
 116 
 117     MethodEntryExitEvents (String args[]) {
 118         super(args);
 119     }
 120 
 121     private void usage(String[] args) throws Exception {
 122         StringBuffer sb = new StringBuffer("Usage: ");
 123         sb.append(System.getProperty("line.separator"));
 124         sb.append("  java ");
 125         sb.append(getClass().getName());
 126         sb.append(" [SUSPEND_NONE | SUSPEND_EVENT_THREAD | SUSPEND_ALL]");
 127         sb.append(" [MethodEntryExitEventsDebugee | -connect <connector options...>] ");
 128         throw new Exception (sb.toString());
 129     }
 130 
 131     public static void main(String[] args)      throws Exception {
 132         MethodEntryExitEvents meee = new MethodEntryExitEvents (args);
 133         meee.startTests();
 134     }
 135 
 136     public void exceptionThrown(ExceptionEvent event) {
 137         System.out.println("Exception: " + event.exception());
 138         System.out.println(" at catch location: " + event.catchLocation());
 139 
 140         // Step to the catch
 141         if (stepReq == null) {
 142             stepReq =
 143                 eventRequestManager().createStepRequest(event.thread(),
 144                                                         StepRequest.STEP_MIN,
 145                                                         StepRequest.STEP_INTO);
 146             stepReq.addCountFilter(1);  // next step only
 147             stepReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
 148         }
 149         stepReq.enable();
 150     }
 151     public void stepCompleted(StepEvent event) {
 152         System.out.println("stepCompleted: line#=" +
 153                            event.location().lineNumber() +
 154                            " event=" + event);
 155         // disable the step and then run to completion
 156         //eventRequestManager().deleteEventRequest(event.request());
 157         StepRequest str= (StepRequest)event.request();
 158         str.disable();
 159     }
 160     public void methodEntered(MethodEntryEvent event) {
 161         if (!includes.contains(event.method().declaringType().name())) {
 162             return;
 163         }
 164 
 165         if (! finishedCounting) {
 166             // We have to count the entry to loopComplete, but
 167             // not the exit
 168             methodEntryCount++;
 169             System.out.print  (" Method entry number: ");
 170             System.out.print  (methodEntryCount);
 171             System.out.print  ("  :  ");
 172             System.out.println(event);
 173             if ("loopComplete".equals(event.method().name())) {
 174                 finishedCounting = true;
 175             }
 176         }
 177     }
 178 
 179     public void methodExited(MethodExitEvent event) {
 180         if (!includes.contains(event.method().declaringType().name())) {
 181             return;
 182         }
 183 
 184         if (! finishedCounting){
 185             methodExitCount++;
 186             System.out.print  (" Method exit  number: ");
 187             System.out.print  (methodExitCount);
 188             System.out.print  ("  :  ");
 189             System.out.println(event);
 190         }
 191     }
 192 
 193     protected void runTests() throws Exception {
 194         if (args.length < 1) {
 195             usage(args);
 196         }
 197         //Pick up the SUSPEND_xxx in first argument
 198         if ("SUSPEND_NONE".equals(args[0])) {
 199             sessionSuspendPolicy = EventRequest.SUSPEND_NONE;
 200         } else if ("SUSPEND_EVENT_THREAD".equals(args[0])) {
 201             sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
 202         } else if ("SUSPEND_ALL".equals(args[0])) {
 203             sessionSuspendPolicy = EventRequest.SUSPEND_ALL;
 204         } else {
 205             usage(args);
 206         }
 207         System.out.print("Suspend policy is: ");
 208         System.out.println(args[0]);
 209 
 210         // Skip the test arg
 211         String[] args2 = new String[args.length - 1];
 212         System.arraycopy(args, 1, args2, 0, args.length - 1);
 213 
 214         if (args2.length < 1) {
 215             usage(args2);
 216         }
 217         List argList = new ArrayList(Arrays.asList(args2));
 218         System.out.println("run args: " + argList);
 219         connect((String[]) argList.toArray(args2));
 220         waitForVMStart();
 221 
 222         // Determine main thread
 223         ClassPrepareEvent e = resumeToPrepareOf("MethodEntryExitEventsDebugee");
 224         mainThread = e.thread();
 225 
 226         try {
 227 
 228             /*
 229              * Ask for Exception events
 230              */
 231             ExceptionRequest exceptionRequest =
 232                 eventRequestManager().createExceptionRequest(null, // refType (null == all instances)
 233                                                              true, // notifyCaught
 234                                                              true);// notifyUncaught
 235             exceptionRequest.addThreadFilter(mainThread);
 236             exceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
 237             exceptionRequest.enable();
 238 
 239             /*
 240              * Ask for method entry events
 241              */
 242             MethodEntryRequest entryRequest =
 243                eventRequestManager().createMethodEntryRequest();
 244             entryRequest.addThreadFilter(mainThread);
 245             entryRequest.setSuspendPolicy(sessionSuspendPolicy);
 246             entryRequest.enable();
 247 
 248             /*
 249              * Ask for method exit events
 250              */
 251             MethodExitRequest exitRequest =
 252                 eventRequestManager().createMethodExitRequest();
 253             exitRequest.addThreadFilter(mainThread);
 254             exitRequest.setSuspendPolicy(sessionSuspendPolicy);
 255             exitRequest.enable();
 256 
 257             /*
 258              * We are now set up to receive the notifications we want.
 259              * Here we go.  This adds 'this' as a listener so
 260              * that our handlers above will be called.
 261              */
 262 
 263             listenUntilVMDisconnect();
 264             System.out.println("All done...");
 265 
 266         } catch (Exception ex){
 267             ex.printStackTrace();
 268             testFailed = true;
 269         }
 270 
 271         if ((methodEntryCount != expectedEntryCount) ||
 272             (methodExitCount != expectedExitCount)) {
 273             testFailed = true;
 274         }
 275         if (!testFailed) {
 276             System.out.println();
 277             System.out.println("MethodEntryExitEvents: passed");
 278             System.out.print  ("    Method entry count: ");
 279             System.out.println(methodEntryCount);
 280             System.out.print  ("    Method exit  count: ");
 281             System.out.println(methodExitCount);
 282         } else {
 283             System.out.println();
 284             System.out.println("MethodEntryExitEvents: failed");
 285             System.out.print  ("    expected method entry count: ");
 286             System.out.println(expectedEntryCount);
 287             System.out.print  ("    observed method entry count: ");
 288             System.out.println(methodEntryCount);
 289             System.out.print  ("    expected method exit  count: ");
 290             System.out.println(expectedExitCount);
 291             System.out.print  ("    observed method exit  count: ");
 292             System.out.println(methodExitCount);
 293             throw new Exception("MethodEntryExitEvents: failed");
 294         }
 295     }
 296 }