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
chk(byte v)134     public static boolean chk(byte v) {
135         return v == (debuggerWatching ? ebyteValue: byteValue);
136     }
chk(char v)137     public static boolean chk(char v) {
138         return v == (debuggerWatching ? echarValue: charValue);
139     }
chk(double v)140     public static boolean chk(double v) {
141         return v == (debuggerWatching ? edoubleValue: doubleValue);
142     }
chk(float v)143     public static boolean chk(float v) {
144         return v == (debuggerWatching ? efloatValue: floatValue);
145     }
chk(int v)146     public static boolean chk(int v) {
147         return v == (debuggerWatching ? eintValue: intValue);
148     }
chk(long v)149     public static boolean chk(long v) {
150         return v == (debuggerWatching ? elongValue: longValue);
151     }
chk(short v)152     public static boolean chk(short v) {
153         return v == (debuggerWatching ? eshortValue: shortValue);
154     }
chk(boolean v)155     public static boolean chk(boolean v) {
156         return v == (debuggerWatching ? ebooleanValue: booleanValue);
157     }
chk(String v)158     public static boolean chk(String v) {
159         return v.equals(debuggerWatching ? estringValue: stringValue);
160     }
chk(Object v)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
s_show(String p1)166     public static String s_show(String p1) { return p1;}
167 
168     // These are the static methods
s_bytef(int p1)169     public static byte s_bytef(int p1){ return byteValue; }
s_charf()170     public static char s_charf()      { return charValue; }
s_doublef()171     public static double s_doublef()  { return doubleValue; }
s_floatf()172     public static float s_floatf()    { return floatValue; }
s_intf()173     public static int s_intf()        { return intValue; }
s_longf()174     public static long s_longf()      { return longValue; }
s_shortf()175     public static short s_shortf()    { return shortValue; }
s_booleanf()176     public static boolean s_booleanf(){ return booleanValue; }
s_stringf()177     public static String s_stringf()  { return stringValue; }
s_classf()178     public static Class s_classf()    { return classValue; }
s_classLoaderf()179     public static ClassLoader s_classLoaderf()
180                                       { return classLoaderValue; }
s_threadf()181     public static Thread s_threadf()  { return threadValue; }
s_threadGroupf()182     public static ThreadGroup s_threadGroupf()
183                                       { return threadGroupValue; }
s_intArrayf()184     public static int[] s_intArrayf() { return intArrayValue; }
s_nullObjectf()185     public static Object s_nullObjectf() { return null; }
s_objectf()186     public static Object s_objectf()  { return objectValue; }
s_voidf()187     public static void s_voidf()      { System.err.println("debugee in s_voidf");}
188 
189     // These are the instance methods
i_bytef(int p1)190     public byte i_bytef(int p1)      { return byteValue; }
i_charf()191     public char i_charf()            { return charValue; }
i_doublef()192     public double i_doublef()        { return doubleValue; }
i_floatf()193     public float i_floatf()          { return floatValue; }
i_intf()194     public int i_intf()              { return intValue; }
i_longf()195     public long i_longf()            { return longValue; }
i_shortf()196     public short i_shortf()          { return shortValue; }
i_booleanf()197     public boolean i_booleanf()      { return booleanValue; }
i_stringf()198     public String i_stringf()        { return stringValue; }
i_classf()199     public Class i_classf()          { return classValue; }
i_classLoaderf()200     public ClassLoader i_classLoaderf()
201                                      { return classLoaderValue; }
i_threadf()202     public Thread i_threadf()        { return threadValue; }
i_threadGroupf()203     public ThreadGroup i_threadGroupf()
204                                      { return threadGroupValue; }
i_intArrayf()205     public int[] i_intArrayf()       { return intArrayValue; }
i_nullObjectf()206     public Object i_nullObjectf()    { return null; }
i_objectf()207     public Object i_objectf()        { return objectValue; }
i_voidf()208     public void i_voidf()            {}
209 
doit(EarlyReturnTarg xx)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 */
hang()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 
main(String[] args)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 
EarlyReturnTest(String args[])307     EarlyReturnTest(String args[]) {
308         super(args);
309     }
310 
main(String[] args)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!
ckByteValue(Value retValue)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 
ckCharValue(Value retValue)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 
ckDoubleValue(Value retValue)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 
ckFloatValue(Value retValue)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 
ckIntValue(Value retValue)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 
ckLongValue(Value retValue)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 
ckShortValue(Value retValue)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 
ckBooleanValue(Value retValue)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 
ckStringValue(Value retValue)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 
ckClassValue(Value retValue)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 
ckClassLoaderValue(Value retValue)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 
ckThreadValue(Value retValue)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 
ckThreadGroupValue(Value retValue)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 
ckArrayValue(Value retValue)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 
ckNullObjectValue(Value retValue)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 
ckObjectValue(Value retValue)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 
ckVoidValue(Value retValue)541     void ckVoidValue(Value retValue) {
542         System.out.println("Passed: Void");
543         earlyReturns++;
544     }
545 
setBreakpoint(String clsName, String methodName, String methodSignature)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 
breakpointReached(BreakpointEvent event)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.
methodExited(MethodExitEvent event)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 
runTests()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 }
807