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 }