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 }