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