1 /* 2 * Copyright (c) 2005, 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 6175634 27 * @summary Allow early return from methods 28 * 29 * @bug 6431720 30 * @summary Unexpected InvalidTypeException when call ThreadReference.forceEarlyReturn with VoidValue 31 * 32 * @bug 6432855 33 * @summary Need a way to create JDI VoidValue for use in ThreadReference.forceEarlyReturn 34 * 35 * @author Tim Bell (based on MethodExitReturnValuesTest by Jim Holmlund) 36 * 37 * @run build TestScaffold VMConnection TargetListener TargetAdapter 38 * @run compile -g EarlyReturnTest.java 39 * @run driver EarlyReturnTest 40 */ 41 import com.sun.jdi.*; 42 import com.sun.jdi.event.*; 43 import com.sun.jdi.request.*; 44 import java.util.*; 45 import java.net.URLClassLoader; 46 import java.net.URL; 47 import java.lang.reflect.Array; 48 49 /* 50 * This test has a debuggee which calls a static method 51 * for each kind of JDI Value, and then an instance method 52 * for each. 53 * 54 * The debugger sets breakpoints in all methods. When a breakpoint 55 * is hit the debugger requests an early return and supplies a new 56 * return value. It then checks that the correct return values are 57 * included in the MethodExitEvents. 58 * 59 * Each value is stored in a static var in the debuggee. The debugger 60 * gets the values from these static vars to check for correct 61 * return values in the MethodExitEvents. 62 */ 63 64 class EarlyReturnTarg { 65 static boolean debuggerWatching = false; 66 static int failureCount = 0; 67 /* 68 * These are the values that will be used by methods 69 * returning normally. 70 */ 71 static URL[] urls = new URL[1]; 72 public static byte byteValue = 89; 73 public static char charValue = 'x'; 74 public static double doubleValue = 2.2; 75 public static float floatValue = 3.3f; 76 public static int intValue = 1; 77 public static long longValue = Long.MAX_VALUE; 78 public static short shortValue = 8; 79 public static boolean booleanValue = false; 80 81 public static Class classValue = Object.class; 82 public static ClassLoader classLoaderValue; 83 { 84 try { 85 urls[0] = new URL("file:/foo"); 86 } catch (java.net.MalformedURLException ex) { 87 throw new AssertionError(ex); 88 } 89 classLoaderValue = new URLClassLoader(urls); 90 } 91 92 public static Thread threadValue = Thread.currentThread(); 93 public static ThreadGroup threadGroupValue = threadValue.getThreadGroup(); 94 public static String stringValue = "abc"; 95 public static int[] intArrayValue = new int[] {1, 2, 3}; 96 97 public static EarlyReturnTarg objectValue = 98 new EarlyReturnTarg(); 99 public String ivar = stringValue; 100 101 /* 102 * These are the values that will be used by methods 103 * returning early. These are != the normal values 104 * defined above. 105 */ 106 static URL[] eurls = new URL[1]; 107 public static byte ebyteValue = 42; 108 public static char echarValue = 'a'; 109 public static double edoubleValue = 6.6; 110 public static float efloatValue = 9.9f; 111 public static int eintValue = 7; 112 public static long elongValue = Long.MIN_VALUE; 113 public static short eshortValue = 3; 114 public static boolean ebooleanValue = true; 115 116 public static Class eclassValue = String.class; 117 public static ClassLoader eclassLoaderValue; 118 { 119 try { 120 urls[0] = new URL("file:/bar"); 121 } catch (java.net.MalformedURLException ex) { 122 throw new AssertionError(ex); 123 } 124 classLoaderValue = new URLClassLoader(urls); 125 } 126 public static Thread ethreadValue; 127 public static ThreadGroup ethreadGroupValue; 128 public static String estringValue = "wxyz"; 129 public static int[] eintArrayValue = new int[] {10, 11, 12}; 130 131 public static java.util.Date eobjectValue = new java.util.Date(); 132 133 // Used to check the return values seen on the debugee side 134 public static boolean chk(byte v) { 135 return v == (debuggerWatching ? ebyteValue: byteValue); 136 } 137 public static boolean chk(char v) { 138 return v == (debuggerWatching ? echarValue: charValue); 139 } 140 public static boolean chk(double v) { 141 return v == (debuggerWatching ? edoubleValue: doubleValue); 142 } 143 public static boolean chk(float v) { 144 return v == (debuggerWatching ? efloatValue: floatValue); 145 } 146 public static boolean chk(int v) { 147 return v == (debuggerWatching ? eintValue: intValue); 148 } 149 public static boolean chk(long v) { 150 return v == (debuggerWatching ? elongValue: longValue); 151 } 152 public static boolean chk(short v) { 153 return v == (debuggerWatching ? eshortValue: shortValue); 154 } 155 public static boolean chk(boolean v) { 156 return v == (debuggerWatching ? ebooleanValue: booleanValue); 157 } 158 public static boolean chk(String v) { 159 return v.equals(debuggerWatching ? estringValue: stringValue); 160 } 161 public static boolean chk(Object v) { 162 return v.equals(debuggerWatching ? eobjectValue: objectValue); 163 } 164 165 // Used to show which set of tests follows 166 public static String s_show(String p1) { return p1;} 167 168 // These are the static methods 169 public static byte s_bytef(int p1){ return byteValue; } 170 public static char s_charf() { return charValue; } 171 public static double s_doublef() { return doubleValue; } 172 public static float s_floatf() { return floatValue; } 173 public static int s_intf() { return intValue; } 174 public static long s_longf() { return longValue; } 175 public static short s_shortf() { return shortValue; } 176 public static boolean s_booleanf(){ return booleanValue; } 177 public static String s_stringf() { return stringValue; } 178 public static Class s_classf() { return classValue; } 179 public static ClassLoader s_classLoaderf() 180 { return classLoaderValue; } 181 public static Thread s_threadf() { return threadValue; } 182 public static ThreadGroup s_threadGroupf() 183 { return threadGroupValue; } 184 public static int[] s_intArrayf() { return intArrayValue; } 185 public static Object s_nullObjectf() { return null; } 186 public static Object s_objectf() { return objectValue; } 187 public static void s_voidf() { System.err.println("debugee in s_voidf");} 188 189 // These are the instance methods 190 public byte i_bytef(int p1) { return byteValue; } 191 public char i_charf() { return charValue; } 192 public double i_doublef() { return doubleValue; } 193 public float i_floatf() { return floatValue; } 194 public int i_intf() { return intValue; } 195 public long i_longf() { return longValue; } 196 public short i_shortf() { return shortValue; } 197 public boolean i_booleanf() { return booleanValue; } 198 public String i_stringf() { return stringValue; } 199 public Class i_classf() { return classValue; } 200 public ClassLoader i_classLoaderf() 201 { return classLoaderValue; } 202 public Thread i_threadf() { return threadValue; } 203 public ThreadGroup i_threadGroupf() 204 { return threadGroupValue; } 205 public int[] i_intArrayf() { return intArrayValue; } 206 public Object i_nullObjectf() { return null; } 207 public Object i_objectf() { return objectValue; } 208 public void i_voidf() {} 209 210 static void doit(EarlyReturnTarg xx) throws Exception { 211 System.err.print("debugee in doit "); 212 if (debuggerWatching) { 213 System.err.println("with a debugger watching. Early returns expected."); 214 } else { 215 System.err.println("with no debugger watching. Normal returns."); 216 } 217 218 s_show("========== Testing static methods ================"); 219 if (!chk( s_bytef(88))) failureCount++; 220 if (!chk( s_charf())) failureCount++; 221 if (!chk( s_doublef())) failureCount++; 222 if (!chk( s_floatf())) failureCount++; 223 if (!chk( s_intf())) failureCount++; 224 if (!chk( s_longf())) failureCount++; 225 if (!chk( s_shortf())) failureCount++; 226 if (!chk( s_booleanf())) failureCount++; 227 228 if (!chk( s_stringf())) failureCount++; 229 s_classf(); 230 s_classLoaderf(); 231 s_threadf(); 232 s_threadGroupf(); 233 s_intArrayf(); 234 s_nullObjectf(); 235 if (!chk( s_objectf())) failureCount++; 236 s_voidf(); 237 238 s_show("========== Testing instance methods ================"); 239 if (!chk( xx.i_bytef(89))) failureCount++; 240 if (!chk( xx.i_charf())) failureCount++; 241 if (!chk( xx.i_doublef())) failureCount++; 242 if (!chk( xx.i_floatf())) failureCount++; 243 if (!chk( xx.i_intf())) failureCount++; 244 if (!chk( xx.i_longf())) failureCount++; 245 if (!chk( xx.i_shortf())) failureCount++; 246 if (!chk( xx.i_booleanf())) failureCount++; 247 if (!chk( xx.i_stringf())) failureCount++; 248 xx.i_intArrayf(); 249 xx.i_classf(); 250 xx.i_classLoaderf(); 251 xx.i_threadf(); 252 xx.i_threadGroupf(); 253 xx.i_nullObjectf(); 254 if (!chk( xx.i_objectf())) failureCount++; 255 xx.i_voidf(); 256 257 } 258 259 /** Hang so that test fails */ 260 static void hang() { 261 try { 262 // ten minute nap 263 Thread.currentThread().sleep(10 * 60 * 1000); 264 } catch (InterruptedException exc) { 265 // shouldn't happen 266 } 267 } 268 269 public static void main(String[] args) throws Exception { 270 // The debugger will stop at the start of main, 271 // set breakpoints and then do a resume. 272 System.err.println("debugee in main"); 273 EarlyReturnTarg xx = 274 new EarlyReturnTarg(); 275 276 doit(xx); 277 if (debuggerWatching && failureCount > 0) { 278 hang(); 279 throw new Exception("EarlyReturnTarg: failed"); 280 } 281 } 282 } 283 284 285 286 public class EarlyReturnTest extends TestScaffold { 287 288 289 /* 290 * Class patterns for which we don't want events (copied 291 * from the "Trace.java" example): 292 * http://java.sun.com/javase/technologies/core/toolsapis/jpda/ 293 */ 294 private String[] excludes = { 295 "javax.*", 296 "sun.*", 297 "com.sun.*", 298 "com.oracle.*", 299 "oracle.*"}; 300 301 static VirtualMachineManager vmm ; 302 ClassType targetClass; 303 Field theValueField; 304 static int earlyReturns = 0; 305 static final int expectedEarlyReturns = 34; // determined by inspection :-) 306 307 EarlyReturnTest(String args[]) { 308 super(args); 309 } 310 311 public static void main(String[] args) throws Exception { 312 EarlyReturnTest meee = new EarlyReturnTest(args); 313 vmm = Bootstrap.virtualMachineManager(); 314 meee.startTests(); 315 } 316 317 // chkXXX methods lifted directly from MethodExitReturnValuesTest 318 // These methods check for correct return values. Thanks, Jim! 319 void ckByteValue(Value retValue) { 320 Field theValueField = targetClass.fieldByName("ebyteValue"); 321 ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); 322 323 byte vv = theValue.value(); 324 byte rv = ((ByteValue)retValue).value(); 325 if (vv != rv) { 326 failure("failure: byte: expected " + vv + ", got " + rv); 327 } else { 328 System.out.println("Passed: byte " + rv); 329 earlyReturns++; 330 } 331 } 332 333 void ckCharValue(Value retValue) { 334 Field theValueField = targetClass.fieldByName("echarValue"); 335 CharValue theValue = (CharValue)targetClass.getValue(theValueField); 336 337 char vv = theValue.value(); 338 char rv = ((CharValue)retValue).value(); 339 if (vv != rv) { 340 failure("failure: char: expected " + vv + ", got " + rv); 341 } else { 342 System.out.println("Passed: char " + rv); 343 earlyReturns++; 344 } 345 } 346 347 void ckDoubleValue(Value retValue) { 348 Field theValueField = targetClass.fieldByName("edoubleValue"); 349 DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); 350 351 double vv = theValue.value(); 352 double rv = ((DoubleValue)retValue).value(); 353 if (vv != rv) { 354 failure("failure: double: expected " + vv + ", got " + rv); 355 } else { 356 System.out.println("Passed: double " + rv); 357 earlyReturns++; 358 } 359 } 360 361 void ckFloatValue(Value retValue) { 362 Field theValueField = targetClass.fieldByName("efloatValue"); 363 FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); 364 365 float vv = theValue.value(); 366 float rv = ((FloatValue)retValue).value(); 367 if (vv != rv) { 368 failure("failure: float: expected " + vv + ", got " + rv); 369 } else { 370 System.out.println("Passed: float " + rv); 371 earlyReturns++; 372 } 373 } 374 375 void ckIntValue(Value retValue) { 376 Field theValueField = targetClass.fieldByName("eintValue"); 377 IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); 378 379 int vv = theValue.value(); 380 int rv = ((IntegerValue)retValue).value(); 381 if (vv != rv) { 382 failure("failure: int: expected " + vv + ", got " + rv); 383 } else { 384 System.out.println("Passed: int " + rv); 385 earlyReturns++; 386 } 387 } 388 389 void ckLongValue(Value retValue) { 390 Field theValueField = targetClass.fieldByName("elongValue"); 391 LongValue theValue = (LongValue)targetClass.getValue(theValueField); 392 393 long vv = theValue.value(); 394 long rv = ((LongValue)retValue).value(); 395 if (vv != rv) { 396 failure("failure: long: expected " + vv + ", got " + rv); 397 } else { 398 System.out.println("Passed: long " + rv); 399 earlyReturns++; 400 } 401 } 402 403 void ckShortValue(Value retValue) { 404 Field theValueField = targetClass.fieldByName("eshortValue"); 405 ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); 406 407 short vv = theValue.value(); 408 short rv = ((ShortValue)retValue).value(); 409 if (vv != rv) { 410 failure("failure: short: expected " + vv + ", got " + rv); 411 } else { 412 System.out.println("Passed: short " + rv); 413 earlyReturns++; 414 } 415 } 416 417 void ckBooleanValue(Value retValue) { 418 Field theValueField = targetClass.fieldByName("ebooleanValue"); 419 BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); 420 421 boolean vv = theValue.value(); 422 boolean rv = ((BooleanValue)retValue).value(); 423 if (vv != rv) { 424 failure("failure: boolean: expected " + vv + ", got " + rv); 425 } else { 426 System.out.println("Passed: boolean " + rv); 427 earlyReturns++; 428 } 429 } 430 431 void ckStringValue(Value retValue) { 432 Field theValueField = targetClass.fieldByName("estringValue"); 433 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 434 435 String vv = theValue.value(); 436 String rv = ((StringReference)retValue).value(); 437 if (vv != rv) { 438 failure("failure: String: expected " + vv + ", got " + rv); 439 } else { 440 System.out.println("Passed: String: " + rv); 441 earlyReturns++; 442 } 443 } 444 445 void ckClassValue(Value retValue) { 446 Field theValueField = targetClass.fieldByName("eclassValue"); 447 ClassObjectReference vv = (ClassObjectReference)targetClass. 448 getValue(theValueField); 449 450 ClassObjectReference rv = (ClassObjectReference)retValue; 451 if (vv != rv) { 452 failure("failure: Class: expected " + vv + ", got " + rv); 453 } else { 454 System.out.println("Passed: Class: " + rv); 455 earlyReturns++; 456 } 457 } 458 459 void ckClassLoaderValue(Value retValue) { 460 Field theValueField = targetClass.fieldByName("eclassLoaderValue"); 461 ClassLoaderReference vv = (ClassLoaderReference)targetClass. 462 getValue(theValueField); 463 464 ClassLoaderReference rv = (ClassLoaderReference)retValue; 465 if (vv != rv) { 466 failure("failure: ClassLoader: expected " + vv + ", got " + rv); 467 } else { 468 System.out.println("Passed: ClassLoader: " + rv); 469 earlyReturns++; 470 } 471 } 472 473 void ckThreadValue(Value retValue) { 474 Field theValueField = targetClass.fieldByName("ethreadValue"); 475 ThreadReference vv = (ThreadReference)targetClass. 476 getValue(theValueField); 477 478 ThreadReference rv = (ThreadReference)retValue; 479 if (vv != rv) { 480 failure("failure: Thread: expected " + vv + ", got " + rv); 481 } else { 482 System.out.println("Passed: Thread: " + rv); 483 earlyReturns++; 484 } 485 } 486 487 void ckThreadGroupValue(Value retValue) { 488 Field theValueField = targetClass.fieldByName("ethreadGroupValue"); 489 ThreadGroupReference vv = (ThreadGroupReference)targetClass. 490 getValue(theValueField); 491 492 ThreadGroupReference rv = (ThreadGroupReference)retValue; 493 if (vv != rv) { 494 failure("failure: ThreadgGroup: expected " + vv + ", got " + rv); 495 } else { 496 System.out.println("Passed: ThreadGroup: " + rv); 497 earlyReturns++; 498 } 499 } 500 501 void ckArrayValue(Value retValue) { 502 Field theValueField = targetClass.fieldByName("eintArrayValue"); 503 ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); 504 IntegerValue theElem2 = (IntegerValue)theValue.getValue(2); 505 506 ArrayReference theRetValue = (ArrayReference)retValue; 507 IntegerValue retElem2 = (IntegerValue)theRetValue.getValue(2); 508 int vv = theElem2.value(); 509 int rv = retElem2.value(); 510 if (vv != rv) { 511 failure("failure: in[2]: expected " + vv + ", got " + rv); 512 } else { 513 System.out.println("Passed: int[2]: " + rv); 514 earlyReturns++; 515 } 516 } 517 518 void ckNullObjectValue(Value retValue) { 519 if (retValue != null) { 520 failure("failure: NullObject: expected " + null + ", got " + retValue); 521 } else { 522 System.out.println("Passed: NullObject: " + retValue); 523 earlyReturns++; 524 } 525 } 526 527 void ckObjectValue(Value retValue) { 528 ObjectReference theRetValue = (ObjectReference)retValue; 529 530 Field theIVarField = targetClass.fieldByName("eobjectValue"); 531 ObjectReference theRetValField = (ObjectReference)targetClass.getValue(theIVarField); 532 533 if (! theRetValue.equals(theRetValField)) { 534 failure("failure: Object: expected " + theIVarField + ", got " + theRetValField); 535 } else { 536 System.out.println("Passed: Object: " + theRetValField); 537 earlyReturns++; 538 } 539 } 540 541 void ckVoidValue(Value retValue) { 542 System.out.println("Passed: Void"); 543 earlyReturns++; 544 } 545 546 public BreakpointRequest setBreakpoint(String clsName, 547 String methodName, 548 String methodSignature) { 549 ReferenceType rt = findReferenceType(clsName); 550 if (rt == null) { 551 rt = resumeToPrepareOf(clsName).referenceType(); 552 } 553 554 Method method = findMethod(rt, methodName, methodSignature); 555 if (method == null) { 556 throw new IllegalArgumentException("Bad method name/signature"); 557 } 558 BreakpointRequest bpr = eventRequestManager().createBreakpointRequest(method.location()); 559 bpr.setSuspendPolicy(EventRequest.SUSPEND_ALL); 560 bpr.enable(); 561 return bpr; 562 } 563 564 public void breakpointReached(BreakpointEvent event) { 565 String origMethodName = event.location().method().name(); 566 String methodName = origMethodName.substring(2); 567 ThreadReference tr = event.thread(); 568 569 if (vm().canForceEarlyReturn()) { 570 571 try { 572 573 if ("bytef".equals(methodName)){ 574 Field theValueField = targetClass.fieldByName("ebyteValue"); 575 ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); 576 tr.forceEarlyReturn(theValue); 577 /* 578 * See what happens if we access the stack after the force 579 * and before the resume. Disabling this since spec says 580 * the stack is undefined. This type of code can be used to 581 * pursue just what that means. 582 * 583 * StackFrame sf = tr.frame(0); 584 * List<Value> ll = sf.getArgumentValues(); 585 * for (Value vv: ll) { 586 * System.out.println("vv = " + vv); 587 * } 588 */ 589 } else if ("charf".equals(methodName)) { 590 Field theValueField = targetClass.fieldByName("echarValue"); 591 CharValue theValue = (CharValue)targetClass.getValue(theValueField); 592 tr.forceEarlyReturn(theValue); 593 } else if ("doublef".equals(methodName)) { 594 Field theValueField = targetClass.fieldByName("edoubleValue"); 595 DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); 596 tr.forceEarlyReturn(theValue); 597 } else if ("floatf".equals(methodName)) { 598 Field theValueField = targetClass.fieldByName("efloatValue"); 599 FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); 600 tr.forceEarlyReturn(theValue); 601 } else if ("intf".equals(methodName)) { 602 Field theValueField = targetClass.fieldByName("eintValue"); 603 IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); 604 tr.forceEarlyReturn(theValue); 605 } else if ("longf".equals(methodName)) { 606 Field theValueField = targetClass.fieldByName("elongValue"); 607 LongValue theValue = (LongValue)targetClass.getValue(theValueField); 608 tr.forceEarlyReturn(theValue); 609 } else if ("shortf".equals(methodName)) { 610 Field theValueField = targetClass.fieldByName("eshortValue"); 611 ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); 612 tr.forceEarlyReturn(theValue); 613 } else if ("booleanf".equals(methodName)) { 614 Field theValueField = targetClass.fieldByName("ebooleanValue"); 615 BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); 616 tr.forceEarlyReturn(theValue); 617 } else if ("stringf".equals(methodName)) { 618 Field theValueField = targetClass.fieldByName("estringValue"); 619 StringReference theValue = (StringReference)targetClass.getValue(theValueField); 620 tr.forceEarlyReturn(theValue); 621 } else if ("classf".equals(methodName)) { 622 Field theValueField = targetClass.fieldByName("eclassValue"); 623 ClassObjectReference theValue = (ClassObjectReference)targetClass.getValue(theValueField); 624 tr.forceEarlyReturn(theValue); 625 } else if ("classLoaderf".equals(methodName)) { 626 Field theValueField = targetClass.fieldByName("eclassLoaderValue"); 627 ClassLoaderReference theValue = (ClassLoaderReference)targetClass.getValue(theValueField); 628 tr.forceEarlyReturn(theValue); 629 } else if ("threadf".equals(methodName)) { 630 Field theValueField = targetClass.fieldByName("ethreadValue"); 631 ThreadReference theValue = (ThreadReference)targetClass.getValue(theValueField); 632 tr.forceEarlyReturn(theValue); 633 } else if ("threadGroupf".equals(methodName)) { 634 Field theValueField = targetClass.fieldByName("ethreadGroupValue"); 635 ThreadGroupReference theValue = (ThreadGroupReference)targetClass.getValue(theValueField); 636 tr.forceEarlyReturn(theValue); 637 } else if ("intArrayf".equals(methodName)) { 638 Field theValueField = targetClass.fieldByName("eintArrayValue"); 639 ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); 640 tr.forceEarlyReturn(theValue); 641 } else if ("nullObjectf".equals(methodName)) { 642 tr.forceEarlyReturn(null); 643 } else if ("objectf".equals(methodName)) { 644 Field theValueField = targetClass.fieldByName("eobjectValue"); 645 ObjectReference theValue = (ObjectReference)targetClass.getValue(theValueField); 646 tr.forceEarlyReturn(theValue); 647 } else if ("voidf".equals(methodName)) { 648 VoidValue theValue = vm().mirrorOfVoid(); 649 tr.forceEarlyReturn(theValue); 650 } else { 651 failure("failure: Unknown methodName: " + origMethodName); 652 } 653 654 } catch (Exception ex) { 655 failure("failure: " + ex.toString()); 656 ex.printStackTrace(); 657 } 658 } else { 659 System.out.println("Cannot force early return for method: " + origMethodName); 660 } 661 } 662 663 // This is the MethodExitEvent handler. 664 public void methodExited(MethodExitEvent event) { 665 String origMethodName = event.method().name(); 666 if (vm().canGetMethodReturnValues()) { 667 Value retValue = event.returnValue(); 668 669 if (!origMethodName.startsWith("s_") && 670 !origMethodName.startsWith("i_")) { 671 // Skip all uninteresting methods 672 return; 673 } 674 675 String methodName = origMethodName.substring(2); 676 if ("show".equals(methodName)) { 677 System.out.println(retValue); 678 return; 679 } 680 681 if ("bytef".equals(methodName)) ckByteValue(retValue); 682 else if ("charf".equals(methodName)) ckCharValue(retValue); 683 else if ("doublef".equals(methodName)) ckDoubleValue(retValue); 684 else if ("floatf".equals(methodName)) ckFloatValue(retValue); 685 else if ("intf".equals(methodName)) ckIntValue(retValue); 686 else if ("longf".equals(methodName)) ckLongValue(retValue); 687 else if ("shortf".equals(methodName)) ckShortValue(retValue); 688 else if ("booleanf".equals(methodName)) ckBooleanValue(retValue); 689 else if ("stringf".equals(methodName)) ckStringValue(retValue); 690 else if ("classf".equals(methodName)) ckClassValue(retValue); 691 else if ("classLoaderf".equals(methodName)) ckClassLoaderValue(retValue); 692 else if ("threadf".equals(methodName)) ckThreadValue(retValue); 693 else if ("threadGroupf".equals(methodName)) ckThreadGroupValue(retValue); 694 else if ("intArrayf".equals(methodName)) ckArrayValue(retValue); 695 else if ("nullObjectf".equals(methodName)) ckNullObjectValue(retValue); 696 else if ("objectf".equals(methodName)) ckObjectValue(retValue); 697 else if ("voidf".equals(methodName)) ckVoidValue(retValue); 698 else { 699 failure("failure: Unknown methodName: " + origMethodName); 700 } 701 } else { 702 System.out.println("Return Value not available for method: " + origMethodName); 703 } 704 } 705 706 protected void runTests() throws Exception { 707 /* 708 * Get to the top of main() 709 * to determine targetClass and mainThread 710 */ 711 712 BreakpointEvent bpe = startToMain("EarlyReturnTarg"); 713 targetClass = (ClassType)bpe.location().declaringType(); 714 mainThread = bpe.thread(); 715 716 /* 717 * Ask for method exit events 718 */ 719 MethodExitRequest exitRequest = 720 eventRequestManager().createMethodExitRequest(); 721 722 for (int i=0; i<excludes.length; ++i) { 723 exitRequest.addClassExclusionFilter(excludes[i]); 724 } 725 int sessionSuspendPolicy = EventRequest.SUSPEND_ALL; 726 //sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 727 //sessionSuspendPolicy = EventRequest.SUSPEND_NONE; 728 exitRequest.setSuspendPolicy(sessionSuspendPolicy); 729 exitRequest.enable(); 730 731 /* 732 * Turn on the flag so debugee knows to check for early 733 * return values instead of regular return values. 734 */ 735 Field flagField = targetClass.fieldByName("debuggerWatching"); 736 targetClass.setValue(flagField, vm().mirrorOf(true)); 737 738 739 /* 740 * We set and enable breakpoints on all of the interesting 741 * methods called by doit(). In the breakpointReached() 742 * handler we force an early return with a different return 743 * value. 744 * 745 * The MethodExitEvent handler will keep score. 746 */ 747 748 setBreakpoint("EarlyReturnTarg", "s_bytef", "(I)B"); 749 setBreakpoint("EarlyReturnTarg", "s_charf", "()C"); 750 setBreakpoint("EarlyReturnTarg", "s_doublef", "()D"); 751 setBreakpoint("EarlyReturnTarg", "s_floatf", "()F"); 752 setBreakpoint("EarlyReturnTarg", "s_intf", "()I"); 753 setBreakpoint("EarlyReturnTarg", "s_longf", "()J"); 754 setBreakpoint("EarlyReturnTarg", "s_shortf", "()S"); 755 setBreakpoint("EarlyReturnTarg", "s_booleanf", "()Z"); 756 757 setBreakpoint("EarlyReturnTarg", "s_stringf", "()Ljava/lang/String;"); 758 setBreakpoint("EarlyReturnTarg", "s_classf", "()Ljava/lang/Class;"); 759 setBreakpoint("EarlyReturnTarg", "s_classLoaderf", "()Ljava/lang/ClassLoader;"); 760 setBreakpoint("EarlyReturnTarg", "s_threadf", "()Ljava/lang/Thread;"); 761 setBreakpoint("EarlyReturnTarg", "s_threadGroupf", "()Ljava/lang/ThreadGroup;"); 762 setBreakpoint("EarlyReturnTarg", "s_intArrayf", "()[I"); 763 setBreakpoint("EarlyReturnTarg", "s_nullObjectf", "()Ljava/lang/Object;"); 764 setBreakpoint("EarlyReturnTarg", "s_objectf", "()Ljava/lang/Object;"); 765 setBreakpoint("EarlyReturnTarg", "s_voidf", "()V"); 766 767 setBreakpoint("EarlyReturnTarg", "i_bytef", "(I)B"); 768 setBreakpoint("EarlyReturnTarg", "i_charf", "()C"); 769 setBreakpoint("EarlyReturnTarg", "i_doublef", "()D"); 770 setBreakpoint("EarlyReturnTarg", "i_floatf", "()F"); 771 setBreakpoint("EarlyReturnTarg", "i_intf", "()I"); 772 setBreakpoint("EarlyReturnTarg", "i_longf", "()J"); 773 setBreakpoint("EarlyReturnTarg", "i_shortf", "()S"); 774 setBreakpoint("EarlyReturnTarg", "i_booleanf", "()Z"); 775 setBreakpoint("EarlyReturnTarg", "i_stringf", "()Ljava/lang/String;"); 776 setBreakpoint("EarlyReturnTarg", "i_intArrayf", "()[I"); 777 setBreakpoint("EarlyReturnTarg", "i_classf", "()Ljava/lang/Class;"); 778 setBreakpoint("EarlyReturnTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;"); 779 setBreakpoint("EarlyReturnTarg", "i_threadf", "()Ljava/lang/Thread;"); 780 setBreakpoint("EarlyReturnTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;"); 781 setBreakpoint("EarlyReturnTarg", "i_nullObjectf", "()Ljava/lang/Object;"); 782 setBreakpoint("EarlyReturnTarg", "i_objectf", "()Ljava/lang/Object;"); 783 setBreakpoint("EarlyReturnTarg", "i_voidf", "()V"); 784 785 /* Here we go. This adds 'this' as a listener so 786 * that our handlers above will be called. 787 */ 788 listenUntilVMDisconnect(); 789 790 if (earlyReturns != expectedEarlyReturns) { 791 failure("failure: Expected " + expectedEarlyReturns + 792 ", but got " + earlyReturns); 793 } 794 System.out.println("All done, " + earlyReturns + " passed"); 795 796 797 if (!testFailed) { 798 System.out.println(); 799 System.out.println("EarlyReturnTest: passed"); 800 } else { 801 System.out.println(); 802 System.out.println("EarlyReturnTest: failed"); 803 throw new Exception("EarlyReturnTest: failed"); 804 } 805 } 806 }