MethodExitReturnValuesTest.java revision 6073:cea72c2bf071
1/* 2 * Copyright (c) 2004, 2012, 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 4195445 6204179 27 * @summary JDWP, JDI: Add return value to Method Exit Event 28 * @author Jim Holmlund 29 * 30 * @run build TestScaffold VMConnection TargetListener TargetAdapter 31 * @run compile -g MethodExitReturnValuesTest.java 32 * @run main MethodExitReturnValuesTest 33 */ 34import com.sun.jdi.*; 35import com.sun.jdi.event.*; 36import com.sun.jdi.request.*; 37import java.util.*; 38import java.net.URLClassLoader; 39import java.net.URL; 40import java.lang.reflect.Array; 41 42/* 43 * This test has a debuggee which calls a static method 44 * for each kind of JDI Value, and then an instance method 45 * for each. 46 * The debugger turns on MethodExitEvents and checks 47 * that the right return values are included in the MethodExitEvents. 48 * Each value is stored in a static var in the debuggee. The debugger 49 * gets the values from these static vars to check for correct 50 * return values in the MethodExitEvents. 51 */ 52 53class MethodExitReturnValuesTarg { 54 // These are the values that will be returned by the methods 55 static URL[] urls = new URL[1]; 56 public static byte byteValue = 89; 57 public static char charValue = 'x'; 58 public static double doubleValue = 2.2; 59 public static float floatValue = 3.3f; 60 public static int intValue = 1; 61 public static long longValue = Long.MAX_VALUE; 62 public static short shortValue = 8; 63 public static boolean booleanValue = false; 64 65 public static Class classValue = Object.class; 66 public static ClassLoader classLoaderValue; 67 { 68 try { 69 urls[0] = new URL("hi there"); 70 } catch (java.net.MalformedURLException ee) { 71 } 72 classLoaderValue = new URLClassLoader(urls); 73 } 74 75 public static Thread threadValue; 76 public static ThreadGroup threadGroupValue; 77 public static String stringValue = "abc"; 78 public static int[] intArrayValue = new int[] {1, 2, 3}; 79 80 public static MethodExitReturnValuesTarg objectValue = 81 new MethodExitReturnValuesTarg(); 82 public String ivar = stringValue; 83 84 // arrays to be used in calls to native methods Array.get...(....) 85 public static byte[] arrByte = new byte[] {byteValue}; 86 public static char[] arrChar = new char[] {charValue}; 87 public static double[] arrDouble = new double[] {doubleValue}; 88 public static float[] arrFloat = new float[] {floatValue}; 89 public static int[] arrInt = new int[] {intValue}; 90 public static long[] arrLong = new long[] {longValue}; 91 public static short[] arrShort = new short[] {shortValue}; 92 public static boolean[] arrBoolean = new boolean[] {booleanValue}; 93 public static Object[] arrObject = new Object[] {objectValue}; 94 95 // Used to show which set of tests follows 96 public static String s_show(String p1) { return p1;} 97 98 // These are the static methods 99 public static byte s_bytef() { return byteValue; } 100 public static char s_charf() { return charValue; } 101 public static double s_doublef() { return doubleValue; } 102 public static float s_floatf() { return floatValue; } 103 public static int s_intf() { return intValue; } 104 public static long s_longf() { return longValue; } 105 public static short s_shortf() { return shortValue; } 106 public static boolean s_booleanf(){ return booleanValue; } 107 public static String s_stringf() { return stringValue; } 108 public static Class s_classf() { return classValue; } 109 public static ClassLoader s_classLoaderf() 110 { return classLoaderValue; } 111 public static Thread s_threadf() { threadValue = Thread.currentThread(); 112 return threadValue; } 113 public static ThreadGroup s_threadGroupf() 114 { threadGroupValue = threadValue.getThreadGroup(); 115 return threadGroupValue; } 116 public static int[] s_intArrayf() { return intArrayValue; } 117 public static Object s_nullObjectf() { return null; } 118 public static Object s_objectf() { return objectValue; } 119 public static void s_voidf() {} 120 121 // These are the instance methods 122 public byte i_bytef() { return byteValue; } 123 public char i_charf() { return charValue; } 124 public double i_doublef() { return doubleValue; } 125 public float i_floatf() { return floatValue; } 126 public int i_intf() { return intValue; } 127 public long i_longf() { return longValue; } 128 public short i_shortf() { return shortValue; } 129 public boolean i_booleanf() { return booleanValue; } 130 public String i_stringf() { return stringValue; } 131 public Class i_classf() { return classValue; } 132 public ClassLoader i_classLoaderf() 133 { return classLoaderValue; } 134 public Thread i_threadf() { return threadValue; } 135 public ThreadGroup i_threadGroupf() 136 { return threadGroupValue; } 137 public int[] i_intArrayf() { return intArrayValue; } 138 public Object i_nullObjectf() { return null; } 139 public Object i_objectf() { return objectValue; } 140 public void i_voidf() {} 141 142 static void doit(MethodExitReturnValuesTarg xx) { 143 s_show("========== Testing static methods ================"); 144 s_bytef(); 145 s_charf(); 146 s_doublef(); 147 s_floatf(); 148 s_intf(); 149 s_longf(); 150 s_shortf(); 151 s_booleanf(); 152 153 s_stringf(); 154 s_classf(); 155 s_classLoaderf(); 156 s_threadf(); 157 s_threadGroupf(); 158 s_intArrayf(); 159 s_nullObjectf(); 160 s_objectf(); 161 s_voidf(); 162 163 s_show("========== Testing instance methods ================"); 164 xx.i_bytef(); 165 xx.i_charf(); 166 xx.i_doublef(); 167 xx.i_floatf(); 168 xx.i_intf(); 169 xx.i_longf(); 170 xx.i_shortf(); 171 xx.i_booleanf(); 172 xx.i_stringf(); 173 xx.i_intArrayf(); 174 xx.i_classf(); 175 xx.i_classLoaderf(); 176 xx.i_threadf(); 177 xx.i_threadGroupf(); 178 xx.i_nullObjectf(); 179 xx.i_objectf(); 180 xx.i_voidf(); 181 182 // Prove it works for native methods too 183 s_show("========== Testing native methods ================"); 184 StrictMath.sin(doubleValue); 185 Array.getByte(arrByte, 0); 186 Array.getChar(arrChar, 0); 187 Array.getDouble(arrDouble, 0); 188 Array.getFloat(arrFloat, 0); 189 Array.getInt(arrInt, 0); 190 Array.getLong(arrLong, 0); 191 Array.getShort(arrShort, 0); 192 Array.getBoolean(arrBoolean, 0); 193 Array.get(arrObject, 0); 194 stringValue.intern(); 195 } 196 197 public static void main(String[] args) { 198 // The debugger will stop at the start of main, 199 // enable method exit events, and then do 200 // a resume. 201 202 MethodExitReturnValuesTarg xx = 203 new MethodExitReturnValuesTarg(); 204 205 doit(xx); 206 } 207} 208 209 210 211public class MethodExitReturnValuesTest extends TestScaffold { 212 213 /* 214 * Class patterns for which we don't want events (copied 215 * from the "Trace.java" example): 216 * http://java.sun.com/javase/technologies/core/toolsapis/jpda/ 217 */ 218 private String[] excludes = { 219 "javax.*", 220 "sun.*", 221 "com.sun.*", 222 "com.oracle.*", 223 "oracle.*"}; 224 225 static VirtualMachineManager vmm ; 226 ClassType targetClass; 227 Field theValueField; 228 static int successes = 0; 229 static final int expectedSuccesses = 44; // determined by inspection :-) 230 231 MethodExitReturnValuesTest(String args[]) { 232 super(args); 233 } 234 235 public static void main(String[] args) throws Exception { 236 MethodExitReturnValuesTest meee = new MethodExitReturnValuesTest(args); 237 vmm = Bootstrap.virtualMachineManager(); 238 meee.startTests(); 239 } 240 241 // These are the methods that check for correct return values. 242 243 void ckByteValue(Value retValue) { 244 Field theValueField = targetClass.fieldByName("byteValue"); 245 ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); 246 247 byte vv = theValue.value(); 248 byte rv = ((ByteValue)retValue).value(); 249 if (vv != rv) { 250 failure("failure: byte: expected " + vv + ", got " + rv); 251 } else { 252 System.out.println("Passed: byte " + rv); 253 successes++; 254 } 255 } 256 257 void ckCharValue(Value retValue) { 258 Field theValueField = targetClass.fieldByName("charValue"); 259 CharValue theValue = (CharValue)targetClass.getValue(theValueField); 260 261 char vv = theValue.value(); 262 char rv = ((CharValue)retValue).value(); 263 if (vv != rv) { 264 failure("failure: char: expected " + vv + ", got " + rv); 265 } else { 266 System.out.println("Passed: char " + rv); 267 successes++; 268 } 269 } 270 271 void ckDoubleValue(Value retValue) { 272 Field theValueField = targetClass.fieldByName("doubleValue"); 273 DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); 274 275 double vv = theValue.value(); 276 double rv = ((DoubleValue)retValue).value(); 277 if (vv != rv) { 278 failure("failure: double: expected " + vv + ", got " + rv); 279 } else { 280 System.out.println("Passed: double " + rv); 281 successes++; 282 } 283 } 284 285 void ckFloatValue(Value retValue) { 286 Field theValueField = targetClass.fieldByName("floatValue"); 287 FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); 288 289 float vv = theValue.value(); 290 float rv = ((FloatValue)retValue).value(); 291 if (vv != rv) { 292 failure("failure: float: expected " + vv + ", got " + rv); 293 } else { 294 System.out.println("Passed: float " + rv); 295 successes++; 296 } 297 } 298 299 void ckIntValue(Value retValue) { 300 Field theValueField = targetClass.fieldByName("intValue"); 301 IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); 302 303 int vv = theValue.value(); 304 int rv = ((IntegerValue)retValue).value(); 305 if (vv != rv) { 306 failure("failure: int: expected " + vv + ", got " + rv); 307 } else { 308 System.out.println("Passed: int " + rv); 309 successes++; 310 } 311 } 312 313 void ckLongValue(Value retValue) { 314 Field theValueField = targetClass.fieldByName("longValue"); 315 LongValue theValue = (LongValue)targetClass.getValue(theValueField); 316 317 long vv = theValue.value(); 318 long rv = ((LongValue)retValue).value(); 319 if (vv != rv) { 320 failure("failure: long: expected " + vv + ", got " + rv); 321 } else { 322 System.out.println("Passed: long " + rv); 323 successes++; 324 } 325 } 326 327 void ckShortValue(Value retValue) { 328 Field theValueField = targetClass.fieldByName("shortValue"); 329 ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); 330 331 short vv = theValue.value(); 332 short rv = ((ShortValue)retValue).value(); 333 if (vv != rv) { 334 failure("failure: short: expected " + vv + ", got " + rv); 335 } else { 336 System.out.println("Passed: short " + rv); 337 successes++; 338 } 339 } 340 341 void ckBooleanValue(Value retValue) { 342 Field theValueField = targetClass.fieldByName("booleanValue"); 343 BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); 344 345 boolean vv = theValue.value(); 346 boolean rv = ((BooleanValue)retValue).value(); 347 if (vv != rv) { 348 failure("failure: boolean: expected " + vv + ", got " + rv); 349 } else { 350 System.out.println("Passed: boolean " + rv); 351 successes++; 352 } 353 } 354 355 void ckStringValue(Value retValue) { 356 Field theValueField = targetClass.fieldByName("stringValue"); 357 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 358 359 String vv = theValue.value(); 360 String rv = ((StringReference)retValue).value(); 361 if (vv != rv) { 362 failure("failure: String: expected " + vv + ", got " + rv); 363 } else { 364 System.out.println("Passed: String: " + rv); 365 successes++; 366 } 367 } 368 369 void ckClassValue(Value retValue) { 370 Field theValueField = targetClass.fieldByName("classValue"); 371 ClassObjectReference vv = (ClassObjectReference)targetClass. 372 getValue(theValueField); 373 374 ClassObjectReference rv = (ClassObjectReference)retValue; 375 if (vv != rv) { 376 failure("failure: Class: expected " + vv + ", got " + rv); 377 } else { 378 System.out.println("Passed: Class: " + rv); 379 successes++; 380 } 381 } 382 383 void ckClassLoaderValue(Value retValue) { 384 Field theValueField = targetClass.fieldByName("classLoaderValue"); 385 ClassLoaderReference vv = (ClassLoaderReference)targetClass. 386 getValue(theValueField); 387 388 ClassLoaderReference rv = (ClassLoaderReference)retValue; 389 if (vv != rv) { 390 failure("failure: ClassLoader: expected " + vv + ", got " + rv); 391 } else { 392 System.out.println("Passed: ClassLoader: " + rv); 393 successes++; 394 } 395 } 396 397 void ckThreadValue(Value retValue) { 398 Field theValueField = targetClass.fieldByName("threadValue"); 399 ThreadReference vv = (ThreadReference)targetClass. 400 getValue(theValueField); 401 402 ThreadReference rv = (ThreadReference)retValue; 403 if (vv != rv) { 404 failure("failure: Thread: expected " + vv + ", got " + rv); 405 } else { 406 System.out.println("Passed: Thread: " + rv); 407 successes++; 408 } 409 } 410 411 void ckThreadGroupValue(Value retValue) { 412 Field theValueField = targetClass.fieldByName("threadGroupValue"); 413 ThreadGroupReference vv = (ThreadGroupReference)targetClass. 414 getValue(theValueField); 415 416 ThreadGroupReference rv = (ThreadGroupReference)retValue; 417 if (vv != rv) { 418 failure("failure: ThreadgGroup: expected " + vv + ", got " + rv); 419 } else { 420 System.out.println("Passed: ThreadGroup: " + rv); 421 successes++; 422 } 423 } 424 425 void ckArrayValue(Value retValue) { 426 Field theValueField = targetClass.fieldByName("intArrayValue"); 427 ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); 428 IntegerValue theElem2 = (IntegerValue)theValue.getValue(2); 429 430 ArrayReference theRetValue = (ArrayReference)retValue; 431 IntegerValue retElem2 = (IntegerValue)theRetValue.getValue(2); 432 int vv = theElem2.value(); 433 int rv = retElem2.value(); 434 if (vv != rv) { 435 failure("failure: in[2]: expected " + vv + ", got " + rv); 436 } else { 437 System.out.println("Passed: int[2]: " + rv); 438 successes++; 439 } 440 } 441 442 void ckNullObjectValue(Value retValue) { 443 if (retValue != null) { 444 failure("failure: NullObject: expected " + null + ", got " + retValue); 445 } else { 446 System.out.println("Passed: NullObject: " + retValue); 447 successes++; 448 } 449 } 450 451 void ckObjectValue(Value retValue) { 452 // We will check the ivar field which we know contains 453 // the value of 'stringValue' 454 Field theValueField = targetClass.fieldByName("stringValue"); 455 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 456 457 Field theIVarField = targetClass.fieldByName("ivar"); 458 ObjectReference theRetValue = (ObjectReference)retValue; 459 StringReference theRetValField = (StringReference)theRetValue.getValue(theIVarField); 460 461 String vv = theValue.value(); 462 String rv = theRetValField.value(); 463 if (vv != rv) { 464 failure("failure: Object: expected " + vv + ", got " + rv); 465 } else { 466 System.out.println("Passed: Object: " + rv); 467 successes++; 468 } 469 } 470 471 void ckVoidValue(Value retValue) { 472 System.out.println("Passed: Void"); 473 successes++; 474 } 475 476 void ckSinValue(Value retValue) { 477 double rv = ((DoubleValue)retValue).value(); 478 double vv = StrictMath.sin(MethodExitReturnValuesTarg.doubleValue); 479 if (rv != vv) { 480 failure("failure: sin: expected " + vv + ", got " + rv); 481 } else { 482 System.out.println("Passed: sin " + rv); 483 successes++; 484 } 485 } 486 487 // This is the MethodExitEvent handler. 488 public void methodExited(MethodExitEvent event) { 489 String origMethodName = event.method().name(); 490 if (vmm.majorInterfaceVersion() >= 1 && 491 vmm.minorInterfaceVersion() >= 6 && 492 vm().canGetMethodReturnValues()) { 493 Value retValue = event.returnValue(); 494 495 if ("sin".equals(origMethodName)) { 496 ckSinValue(retValue); 497 return; 498 } 499 500 if (!origMethodName.startsWith("s_") && 501 !origMethodName.startsWith("i_")) { 502 // Check native methods 503 if ("getByte".equals(origMethodName)) ckByteValue(retValue); 504 else if ("getChar".equals(origMethodName)) ckCharValue(retValue); 505 else if ("getDouble".equals(origMethodName)) ckDoubleValue(retValue); 506 else if ("getFloat".equals(origMethodName)) ckFloatValue(retValue); 507 else if ("getInt".equals(origMethodName)) ckIntValue(retValue); 508 else if ("getLong".equals(origMethodName)) ckLongValue(retValue); 509 else if ("getShort".equals(origMethodName)) ckShortValue(retValue); 510 else if ("getBoolean".equals(origMethodName)) ckBooleanValue(retValue); 511 else if ("getObject".equals(origMethodName)) ckObjectValue(retValue); 512 else if ("intern".equals(origMethodName)) ckStringValue(retValue); 513 return; 514 } 515 516 String methodName = origMethodName.substring(2); 517 if ("show".equals(methodName)) { 518 System.out.println(retValue); 519 return; 520 } 521 522 if ("bytef".equals(methodName)) ckByteValue(retValue); 523 else if ("charf".equals(methodName)) ckCharValue(retValue); 524 else if ("doublef".equals(methodName)) ckDoubleValue(retValue); 525 else if ("floatf".equals(methodName)) ckFloatValue(retValue); 526 else if ("intf".equals(methodName)) ckIntValue(retValue); 527 else if ("longf".equals(methodName)) ckLongValue(retValue); 528 else if ("shortf".equals(methodName)) ckShortValue(retValue); 529 else if ("booleanf".equals(methodName)) ckBooleanValue(retValue); 530 else if ("stringf".equals(methodName)) ckStringValue(retValue); 531 else if ("classf".equals(methodName)) ckClassValue(retValue); 532 else if ("classLoaderf".equals(methodName)) ckClassLoaderValue(retValue); 533 else if ("threadf".equals(methodName)) ckThreadValue(retValue); 534 else if ("threadGroupf".equals(methodName)) ckThreadGroupValue(retValue); 535 else if ("intArrayf".equals(methodName)) ckArrayValue(retValue); 536 else if ("nullObjectf".equals(methodName)) ckNullObjectValue(retValue); 537 else if ("objectf".equals(methodName)) ckObjectValue(retValue); 538 else if ("voidf".equals(methodName)) ckVoidValue(retValue); 539 else { 540 failure("failure: Unknown methodName: " + origMethodName); 541 } 542 } else { 543 System.out.println("Return Value not available for method: " + origMethodName); 544 } 545 } 546 547 protected void runTests() throws Exception { 548 /* 549 * Get to the top of main() 550 * to determine targetClass and mainThread 551 */ 552 BreakpointEvent bpe = startToMain("MethodExitReturnValuesTarg"); 553 targetClass = (ClassType)bpe.location().declaringType(); 554 mainThread = bpe.thread(); 555 556 theValueField = targetClass.fieldByName("theValue"); 557 558 /* 559 * Ask for method exit events 560 */ 561 MethodExitRequest exitRequest = 562 eventRequestManager().createMethodExitRequest(); 563 564 for (int i=0; i<excludes.length; ++i) { 565 exitRequest.addClassExclusionFilter(excludes[i]); 566 } 567 int sessionSuspendPolicy = EventRequest.SUSPEND_ALL; 568 //sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 569 //sessionSuspendPolicy = EventRequest.SUSPEND_NONE; 570 exitRequest.setSuspendPolicy(sessionSuspendPolicy); 571 exitRequest.enable(); 572 573 /* 574 * We are now set up to receive the notifications we want. 575 * Here we go. This adds 'this' as a listener so 576 * that our handlers above will be called. 577 */ 578 579 listenUntilVMDisconnect(); 580 581 if (successes != expectedSuccesses) { 582 failure("failure: Expected " + expectedSuccesses + ", but got " + successes); 583 } 584 System.out.println("All done, " + successes + " passed"); 585 586 587 if (!testFailed) { 588 System.out.println(); 589 System.out.println("MethodExitReturnValuesTest: passed"); 590 } else { 591 System.out.println(); 592 System.out.println("MethodExitReturnValuesTest: failed"); 593 throw new Exception("MethodExitReturnValuesTest: failed"); 594 } 595 } 596} 597