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