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