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 */
41import com.sun.jdi.*;
42import com.sun.jdi.event.*;
43import com.sun.jdi.request.*;
44import java.util.*;
45import java.net.URLClassLoader;
46import java.net.URL;
47import 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
64class 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
284public 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}
805