1 /* 2 * Copyright (c) 2004, 2016, 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 driver MethodExitReturnValuesTest 33 */ 34 import com.sun.jdi.*; 35 import com.sun.jdi.event.*; 36 import com.sun.jdi.request.*; 37 import java.util.*; 38 import java.net.URLClassLoader; 39 import java.net.URL; 40 import 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 53 class 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 211 public class MethodExitReturnValuesTest extends TestScaffold { 212 // Classes which we are interested in 213 private List includes = Arrays.asList(new String[] { 214 "MethodExitReturnValuesTarg", 215 "java.lang.reflect.Array", 216 "java.lang.StrictMath", 217 "java.lang.String" 218 }); 219 220 static VirtualMachineManager vmm ; 221 ClassType targetClass; 222 Field theValueField; 223 static int successes = 0; 224 static final int expectedSuccesses = 44; // determined by inspection :-) 225 226 MethodExitReturnValuesTest(String args[]) { 227 super(args); 228 } 229 230 public static void main(String[] args) throws Exception { 231 MethodExitReturnValuesTest meee = new MethodExitReturnValuesTest(args); 232 vmm = Bootstrap.virtualMachineManager(); 233 meee.startTests(); 234 } 235 236 // These are the methods that check for correct return values. 237 238 void ckByteValue(Value retValue) { 239 Field theValueField = targetClass.fieldByName("byteValue"); 240 ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); 241 242 byte vv = theValue.value(); 243 byte rv = ((ByteValue)retValue).value(); 244 if (vv != rv) { 245 failure("failure: byte: expected " + vv + ", got " + rv); 246 } else { 247 System.out.println("Passed: byte " + rv); 248 successes++; 249 } 250 } 251 252 void ckCharValue(Value retValue) { 253 Field theValueField = targetClass.fieldByName("charValue"); 254 CharValue theValue = (CharValue)targetClass.getValue(theValueField); 255 256 char vv = theValue.value(); 257 char rv = ((CharValue)retValue).value(); 258 if (vv != rv) { 259 failure("failure: char: expected " + vv + ", got " + rv); 260 } else { 261 System.out.println("Passed: char " + rv); 262 successes++; 263 } 264 } 265 266 void ckDoubleValue(Value retValue) { 267 Field theValueField = targetClass.fieldByName("doubleValue"); 268 DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); 269 270 double vv = theValue.value(); 271 double rv = ((DoubleValue)retValue).value(); 272 if (vv != rv) { 273 failure("failure: double: expected " + vv + ", got " + rv); 274 } else { 275 System.out.println("Passed: double " + rv); 276 successes++; 277 } 278 } 279 280 void ckFloatValue(Value retValue) { 281 Field theValueField = targetClass.fieldByName("floatValue"); 282 FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); 283 284 float vv = theValue.value(); 285 float rv = ((FloatValue)retValue).value(); 286 if (vv != rv) { 287 failure("failure: float: expected " + vv + ", got " + rv); 288 } else { 289 System.out.println("Passed: float " + rv); 290 successes++; 291 } 292 } 293 294 void ckIntValue(Value retValue) { 295 Field theValueField = targetClass.fieldByName("intValue"); 296 IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); 297 298 int vv = theValue.value(); 299 int rv = ((IntegerValue)retValue).value(); 300 if (vv != rv) { 301 failure("failure: int: expected " + vv + ", got " + rv); 302 } else { 303 System.out.println("Passed: int " + rv); 304 successes++; 305 } 306 } 307 308 void ckLongValue(Value retValue) { 309 Field theValueField = targetClass.fieldByName("longValue"); 310 LongValue theValue = (LongValue)targetClass.getValue(theValueField); 311 312 long vv = theValue.value(); 313 long rv = ((LongValue)retValue).value(); 314 if (vv != rv) { 315 failure("failure: long: expected " + vv + ", got " + rv); 316 } else { 317 System.out.println("Passed: long " + rv); 318 successes++; 319 } 320 } 321 322 void ckShortValue(Value retValue) { 323 Field theValueField = targetClass.fieldByName("shortValue"); 324 ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); 325 326 short vv = theValue.value(); 327 short rv = ((ShortValue)retValue).value(); 328 if (vv != rv) { 329 failure("failure: short: expected " + vv + ", got " + rv); 330 } else { 331 System.out.println("Passed: short " + rv); 332 successes++; 333 } 334 } 335 336 void ckBooleanValue(Value retValue) { 337 Field theValueField = targetClass.fieldByName("booleanValue"); 338 BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); 339 340 boolean vv = theValue.value(); 341 boolean rv = ((BooleanValue)retValue).value(); 342 if (vv != rv) { 343 failure("failure: boolean: expected " + vv + ", got " + rv); 344 } else { 345 System.out.println("Passed: boolean " + rv); 346 successes++; 347 } 348 } 349 350 void ckStringValue(Value retValue) { 351 Field theValueField = targetClass.fieldByName("stringValue"); 352 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 353 354 String vv = theValue.value(); 355 String rv = ((StringReference)retValue).value(); 356 if (vv != rv) { 357 failure("failure: String: expected " + vv + ", got " + rv); 358 } else { 359 System.out.println("Passed: String: " + rv); 360 successes++; 361 } 362 } 363 364 void ckClassValue(Value retValue) { 365 Field theValueField = targetClass.fieldByName("classValue"); 366 ClassObjectReference vv = (ClassObjectReference)targetClass. 367 getValue(theValueField); 368 369 ClassObjectReference rv = (ClassObjectReference)retValue; 370 if (vv != rv) { 371 failure("failure: Class: expected " + vv + ", got " + rv); 372 } else { 373 System.out.println("Passed: Class: " + rv); 374 successes++; 375 } 376 } 377 378 void ckClassLoaderValue(Value retValue) { 379 Field theValueField = targetClass.fieldByName("classLoaderValue"); 380 ClassLoaderReference vv = (ClassLoaderReference)targetClass. 381 getValue(theValueField); 382 383 ClassLoaderReference rv = (ClassLoaderReference)retValue; 384 if (vv != rv) { 385 failure("failure: ClassLoader: expected " + vv + ", got " + rv); 386 } else { 387 System.out.println("Passed: ClassLoader: " + rv); 388 successes++; 389 } 390 } 391 392 void ckThreadValue(Value retValue) { 393 Field theValueField = targetClass.fieldByName("threadValue"); 394 ThreadReference vv = (ThreadReference)targetClass. 395 getValue(theValueField); 396 397 ThreadReference rv = (ThreadReference)retValue; 398 if (vv != rv) { 399 failure("failure: Thread: expected " + vv + ", got " + rv); 400 } else { 401 System.out.println("Passed: Thread: " + rv); 402 successes++; 403 } 404 } 405 406 void ckThreadGroupValue(Value retValue) { 407 Field theValueField = targetClass.fieldByName("threadGroupValue"); 408 ThreadGroupReference vv = (ThreadGroupReference)targetClass. 409 getValue(theValueField); 410 411 ThreadGroupReference rv = (ThreadGroupReference)retValue; 412 if (vv != rv) { 413 failure("failure: ThreadgGroup: expected " + vv + ", got " + rv); 414 } else { 415 System.out.println("Passed: ThreadGroup: " + rv); 416 successes++; 417 } 418 } 419 420 void ckArrayValue(Value retValue) { 421 Field theValueField = targetClass.fieldByName("intArrayValue"); 422 ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); 423 IntegerValue theElem2 = (IntegerValue)theValue.getValue(2); 424 425 ArrayReference theRetValue = (ArrayReference)retValue; 426 IntegerValue retElem2 = (IntegerValue)theRetValue.getValue(2); 427 int vv = theElem2.value(); 428 int rv = retElem2.value(); 429 if (vv != rv) { 430 failure("failure: in[2]: expected " + vv + ", got " + rv); 431 } else { 432 System.out.println("Passed: int[2]: " + rv); 433 successes++; 434 } 435 } 436 437 void ckNullObjectValue(Value retValue) { 438 if (retValue != null) { 439 failure("failure: NullObject: expected " + null + ", got " + retValue); 440 } else { 441 System.out.println("Passed: NullObject: " + retValue); 442 successes++; 443 } 444 } 445 446 void ckObjectValue(Value retValue) { 447 // We will check the ivar field which we know contains 448 // the value of 'stringValue' 449 Field theValueField = targetClass.fieldByName("stringValue"); 450 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 451 452 Field theIVarField = targetClass.fieldByName("ivar"); 453 ObjectReference theRetValue = (ObjectReference)retValue; 454 StringReference theRetValField = (StringReference)theRetValue.getValue(theIVarField); 455 456 String vv = theValue.value(); 457 String rv = theRetValField.value(); 458 if (vv != rv) { 459 failure("failure: Object: expected " + vv + ", got " + rv); 460 } else { 461 System.out.println("Passed: Object: " + rv); 462 successes++; 463 } 464 } 465 466 void ckVoidValue(Value retValue) { 467 System.out.println("Passed: Void"); 468 successes++; 469 } 470 471 void ckSinValue(Value retValue) { 472 double rv = ((DoubleValue)retValue).value(); 473 double vv = StrictMath.sin(MethodExitReturnValuesTarg.doubleValue); 474 if (rv != vv) { 475 failure("failure: sin: expected " + vv + ", got " + rv); 476 } else { 477 System.out.println("Passed: sin " + rv); 478 successes++; 479 } 480 } 481 482 // This is the MethodExitEvent handler. 483 public void methodExited(MethodExitEvent event) { 484 String origMethodName = event.method().name(); 485 486 if (!includes.contains(event.method().declaringType().name())) { 487 return; 488 } 489 490 if (vm().canGetMethodReturnValues()) { 491 Value retValue = event.returnValue(); 492 493 if ("sin".equals(origMethodName)) { 494 ckSinValue(retValue); 495 return; 496 } 497 498 if (!origMethodName.startsWith("s_") && 499 !origMethodName.startsWith("i_")) { 500 // Check native methods 501 if ("getByte".equals(origMethodName)) ckByteValue(retValue); 502 else if ("getChar".equals(origMethodName)) ckCharValue(retValue); 503 else if ("getDouble".equals(origMethodName)) ckDoubleValue(retValue); 504 else if ("getFloat".equals(origMethodName)) ckFloatValue(retValue); 505 else if ("getInt".equals(origMethodName)) ckIntValue(retValue); 506 else if ("getLong".equals(origMethodName)) ckLongValue(retValue); 507 else if ("getShort".equals(origMethodName)) ckShortValue(retValue); 508 else if ("getBoolean".equals(origMethodName)) ckBooleanValue(retValue); 509 else if ("getObject".equals(origMethodName)) ckObjectValue(retValue); 510 else if ("intern".equals(origMethodName)) ckStringValue(retValue); 511 return; 512 } 513 514 String methodName = origMethodName.substring(2); 515 if ("show".equals(methodName)) { 516 System.out.println(retValue); 517 return; 518 } 519 520 if ("bytef".equals(methodName)) ckByteValue(retValue); 521 else if ("charf".equals(methodName)) ckCharValue(retValue); 522 else if ("doublef".equals(methodName)) ckDoubleValue(retValue); 523 else if ("floatf".equals(methodName)) ckFloatValue(retValue); 524 else if ("intf".equals(methodName)) ckIntValue(retValue); 525 else if ("longf".equals(methodName)) ckLongValue(retValue); 526 else if ("shortf".equals(methodName)) ckShortValue(retValue); 527 else if ("booleanf".equals(methodName)) ckBooleanValue(retValue); 528 else if ("stringf".equals(methodName)) ckStringValue(retValue); 529 else if ("classf".equals(methodName)) ckClassValue(retValue); 530 else if ("classLoaderf".equals(methodName)) ckClassLoaderValue(retValue); 531 else if ("threadf".equals(methodName)) ckThreadValue(retValue); 532 else if ("threadGroupf".equals(methodName)) ckThreadGroupValue(retValue); 533 else if ("intArrayf".equals(methodName)) ckArrayValue(retValue); 534 else if ("nullObjectf".equals(methodName)) ckNullObjectValue(retValue); 535 else if ("objectf".equals(methodName)) ckObjectValue(retValue); 536 else if ("voidf".equals(methodName)) ckVoidValue(retValue); 537 else { 538 failure("failure: Unknown methodName: " + origMethodName); 539 } 540 } else { 541 System.out.println("Return Value not available for method: " + origMethodName); 542 } 543 } 544 545 protected void runTests() throws Exception { 546 /* 547 * Get to the top of main() 548 * to determine targetClass and mainThread 549 */ 550 BreakpointEvent bpe = startToMain("MethodExitReturnValuesTarg"); 551 targetClass = (ClassType)bpe.location().declaringType(); 552 mainThread = bpe.thread(); 553 554 theValueField = targetClass.fieldByName("theValue"); 555 556 /* 557 * Ask for method exit events 558 */ 559 MethodExitRequest exitRequest = 560 eventRequestManager().createMethodExitRequest(); 561 exitRequest.addThreadFilter(mainThread); 562 563 int sessionSuspendPolicy = EventRequest.SUSPEND_ALL; 564 //sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 565 //sessionSuspendPolicy = EventRequest.SUSPEND_NONE; 566 exitRequest.setSuspendPolicy(sessionSuspendPolicy); 567 exitRequest.enable(); 568 569 /* 570 * We are now set up to receive the notifications we want. 571 * Here we go. This adds 'this' as a listener so 572 * that our handlers above will be called. 573 */ 574 575 listenUntilVMDisconnect(); 576 577 if (successes != expectedSuccesses) { 578 failure("failure: Expected " + expectedSuccesses + ", but got " + successes); 579 } 580 System.out.println("All done, " + successes + " passed"); 581 582 583 if (!testFailed) { 584 System.out.println(); 585 System.out.println("MethodExitReturnValuesTest: passed"); 586 } else { 587 System.out.println(); 588 System.out.println("MethodExitReturnValuesTest: failed"); 589 throw new Exception("MethodExitReturnValuesTest: failed"); 590 } 591 } 592 }