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