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