MethodExitReturnValuesTest.java revision 6073:cea72c2bf071
1/*
2 * Copyright (c) 2004, 2012, 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 4195445 6204179
27 *  @summary JDWP, JDI: Add return value to Method Exit Event
28 *  @author Jim Holmlund
29 *
30 *  @run build TestScaffold VMConnection TargetListener TargetAdapter
31 *  @run compile -g MethodExitReturnValuesTest.java
32 *  @run main MethodExitReturnValuesTest
33 */
34import com.sun.jdi.*;
35import com.sun.jdi.event.*;
36import com.sun.jdi.request.*;
37import java.util.*;
38import java.net.URLClassLoader;
39import java.net.URL;
40import java.lang.reflect.Array;
41
42/*
43 * This test has a debuggee which calls a static method
44 * for each kind of JDI Value, and then an instance method
45 * for each.
46 * The debugger turns on MethodExitEvents and checks
47 * that the right return values are included in the MethodExitEvents.
48 * Each value is stored in a static var in the debuggee.  The debugger
49 * gets the values from these static vars to check for correct
50 * return values in the MethodExitEvents.
51 */
52
53class MethodExitReturnValuesTarg {
54    // These are the values that will be returned by the methods
55    static URL[] urls = new URL[1];
56    public static byte      byteValue = 89;
57    public static char      charValue = 'x';
58    public static double    doubleValue = 2.2;
59    public static float     floatValue = 3.3f;
60    public static int       intValue = 1;
61    public static long      longValue = Long.MAX_VALUE;
62    public static short     shortValue = 8;
63    public static boolean   booleanValue = false;
64
65    public static Class       classValue = Object.class;
66    public static ClassLoader classLoaderValue;
67    {
68        try {
69            urls[0] = new URL("hi there");
70        } catch (java.net.MalformedURLException ee) {
71        }
72        classLoaderValue = new URLClassLoader(urls);
73    }
74
75    public static Thread      threadValue;
76    public static ThreadGroup threadGroupValue;
77    public static String      stringValue = "abc";
78    public static int[]       intArrayValue = new int[] {1, 2, 3};
79
80    public static MethodExitReturnValuesTarg  objectValue =
81        new MethodExitReturnValuesTarg();
82    public String ivar = stringValue;
83
84    // arrays to be used in calls to native methods Array.get...(....)
85    public static byte[]    arrByte      = new byte[]    {byteValue};
86    public static char[]    arrChar      = new char[]    {charValue};
87    public static double[]  arrDouble    = new double[]  {doubleValue};
88    public static float[]   arrFloat     = new float[]   {floatValue};
89    public static int[]     arrInt       = new int[]     {intValue};
90    public static long[]    arrLong      = new long[]    {longValue};
91    public static short[]   arrShort     = new short[]   {shortValue};
92    public static boolean[] arrBoolean   = new boolean[] {booleanValue};
93    public static Object[]  arrObject    = new Object[]  {objectValue};
94
95    // Used to show which set of tests follows
96    public static String s_show(String p1) { return p1;}
97
98    // These are the static methods
99    public static byte s_bytef()      { return byteValue; }
100    public static char s_charf()      { return charValue; }
101    public static double s_doublef()  { return doubleValue; }
102    public static float s_floatf()    { return floatValue; }
103    public static int s_intf()        { return intValue; }
104    public static long s_longf()      { return longValue; }
105    public static short s_shortf()    { return shortValue; }
106    public static boolean s_booleanf(){ return booleanValue; }
107    public static String s_stringf()  { return stringValue; }
108    public static Class s_classf()    { return classValue; }
109    public static ClassLoader s_classLoaderf()
110                                      { return classLoaderValue; }
111    public static Thread s_threadf()  { threadValue = Thread.currentThread();
112                                        return threadValue; }
113    public static ThreadGroup s_threadGroupf()
114                                      { threadGroupValue = threadValue.getThreadGroup();
115                                        return threadGroupValue; }
116    public static int[] s_intArrayf() { return intArrayValue; }
117    public static Object s_nullObjectf() { return null; }
118    public static Object s_objectf()  { return objectValue; }
119    public static void s_voidf()      {}
120
121    // These are the instance methods
122    public byte i_bytef()            { return byteValue; }
123    public char i_charf()            { return charValue; }
124    public double i_doublef()        { return doubleValue; }
125    public float i_floatf()          { return floatValue; }
126    public int i_intf()              { return intValue; }
127    public long i_longf()            { return longValue; }
128    public short i_shortf()          { return shortValue; }
129    public boolean i_booleanf()      { return booleanValue; }
130    public String i_stringf()        { return stringValue; }
131    public Class i_classf()          { return classValue; }
132    public ClassLoader i_classLoaderf()
133                                     { return classLoaderValue; }
134    public Thread i_threadf()        { return threadValue; }
135    public ThreadGroup i_threadGroupf()
136                                     { return threadGroupValue; }
137    public int[] i_intArrayf()       { return intArrayValue; }
138    public Object i_nullObjectf()    { return null; }
139    public Object i_objectf()        { return objectValue; }
140    public void i_voidf()            {}
141
142    static void doit(MethodExitReturnValuesTarg xx) {
143        s_show("==========  Testing static methods ================");
144        s_bytef();
145        s_charf();
146        s_doublef();
147        s_floatf();
148        s_intf();
149        s_longf();
150        s_shortf();
151        s_booleanf();
152
153        s_stringf();
154        s_classf();
155        s_classLoaderf();
156        s_threadf();
157        s_threadGroupf();
158        s_intArrayf();
159        s_nullObjectf();
160        s_objectf();
161        s_voidf();
162
163        s_show("==========  Testing instance methods ================");
164        xx.i_bytef();
165        xx.i_charf();
166        xx.i_doublef();
167        xx.i_floatf();
168        xx.i_intf();
169        xx.i_longf();
170        xx.i_shortf();
171        xx.i_booleanf();
172        xx.i_stringf();
173        xx.i_intArrayf();
174        xx.i_classf();
175        xx.i_classLoaderf();
176        xx.i_threadf();
177        xx.i_threadGroupf();
178        xx.i_nullObjectf();
179        xx.i_objectf();
180        xx.i_voidf();
181
182        // Prove it works for native methods too
183        s_show("==========  Testing native methods ================");
184        StrictMath.sin(doubleValue);
185        Array.getByte(arrByte, 0);
186        Array.getChar(arrChar, 0);
187        Array.getDouble(arrDouble, 0);
188        Array.getFloat(arrFloat, 0);
189        Array.getInt(arrInt, 0);
190        Array.getLong(arrLong, 0);
191        Array.getShort(arrShort, 0);
192        Array.getBoolean(arrBoolean, 0);
193        Array.get(arrObject, 0);
194        stringValue.intern();
195    }
196
197    public static void main(String[] args) {
198        // The debugger will stop at the start of main,
199        // enable method exit events, and then do
200        // a resume.
201
202        MethodExitReturnValuesTarg xx =
203            new MethodExitReturnValuesTarg();
204
205        doit(xx);
206    }
207}
208
209
210
211public class MethodExitReturnValuesTest extends TestScaffold {
212
213    /*
214     * Class patterns for which we don't want events (copied
215     * from the "Trace.java" example):
216     *     http://java.sun.com/javase/technologies/core/toolsapis/jpda/
217     */
218    private String[] excludes = {
219        "javax.*",
220        "sun.*",
221        "com.sun.*",
222        "com.oracle.*",
223        "oracle.*"};
224
225    static VirtualMachineManager vmm ;
226    ClassType targetClass;
227    Field theValueField;
228    static int successes = 0;
229    static final int expectedSuccesses = 44;  // determined by inspection :-)
230
231    MethodExitReturnValuesTest(String args[]) {
232        super(args);
233    }
234
235    public static void main(String[] args)      throws Exception {
236        MethodExitReturnValuesTest meee = new MethodExitReturnValuesTest(args);
237        vmm = Bootstrap.virtualMachineManager();
238        meee.startTests();
239    }
240
241    // These are the methods that check for correct return values.
242
243    void ckByteValue(Value retValue) {
244        Field theValueField = targetClass.fieldByName("byteValue");
245        ByteValue theValue = (ByteValue)targetClass.getValue(theValueField);
246
247        byte vv = theValue.value();
248        byte rv = ((ByteValue)retValue).value();
249        if (vv != rv) {
250            failure("failure: byte: expected " + vv + ", got " + rv);
251        } else {
252            System.out.println("Passed: byte " + rv);
253            successes++;
254        }
255    }
256
257    void ckCharValue(Value retValue) {
258        Field theValueField = targetClass.fieldByName("charValue");
259        CharValue theValue = (CharValue)targetClass.getValue(theValueField);
260
261        char vv = theValue.value();
262        char rv = ((CharValue)retValue).value();
263        if (vv != rv) {
264            failure("failure: char: expected " + vv + ", got " + rv);
265        } else {
266            System.out.println("Passed: char " + rv);
267            successes++;
268        }
269    }
270
271    void ckDoubleValue(Value retValue) {
272        Field theValueField = targetClass.fieldByName("doubleValue");
273        DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField);
274
275        double vv = theValue.value();
276        double rv = ((DoubleValue)retValue).value();
277        if (vv != rv) {
278            failure("failure: double: expected " + vv + ", got " + rv);
279        } else {
280            System.out.println("Passed: double " + rv);
281            successes++;
282        }
283    }
284
285    void ckFloatValue(Value retValue) {
286        Field theValueField = targetClass.fieldByName("floatValue");
287        FloatValue theValue = (FloatValue)targetClass.getValue(theValueField);
288
289        float vv = theValue.value();
290        float rv = ((FloatValue)retValue).value();
291        if (vv != rv) {
292            failure("failure: float: expected " + vv + ", got " + rv);
293        } else {
294            System.out.println("Passed: float " + rv);
295            successes++;
296        }
297    }
298
299    void ckIntValue(Value retValue) {
300        Field theValueField = targetClass.fieldByName("intValue");
301        IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField);
302
303        int vv = theValue.value();
304        int rv = ((IntegerValue)retValue).value();
305        if (vv != rv) {
306            failure("failure: int: expected " + vv + ", got " + rv);
307        } else {
308            System.out.println("Passed: int " + rv);
309            successes++;
310        }
311    }
312
313    void ckLongValue(Value retValue) {
314        Field theValueField = targetClass.fieldByName("longValue");
315        LongValue theValue = (LongValue)targetClass.getValue(theValueField);
316
317        long vv = theValue.value();
318        long rv = ((LongValue)retValue).value();
319        if (vv != rv) {
320            failure("failure: long: expected " + vv + ", got " + rv);
321        } else {
322            System.out.println("Passed: long " + rv);
323            successes++;
324        }
325    }
326
327    void ckShortValue(Value retValue) {
328        Field theValueField = targetClass.fieldByName("shortValue");
329        ShortValue theValue = (ShortValue)targetClass.getValue(theValueField);
330
331        short vv = theValue.value();
332        short rv = ((ShortValue)retValue).value();
333        if (vv != rv) {
334            failure("failure: short: expected " + vv + ", got " + rv);
335        } else {
336            System.out.println("Passed: short " + rv);
337            successes++;
338        }
339    }
340
341    void ckBooleanValue(Value retValue) {
342        Field theValueField = targetClass.fieldByName("booleanValue");
343        BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField);
344
345        boolean vv = theValue.value();
346        boolean rv = ((BooleanValue)retValue).value();
347        if (vv != rv) {
348            failure("failure: boolean: expected " + vv + ", got " + rv);
349        } else {
350            System.out.println("Passed: boolean " + rv);
351            successes++;
352        }
353    }
354
355    void ckStringValue(Value retValue) {
356        Field theValueField = targetClass.fieldByName("stringValue");
357        StringReference theValue = (StringReference)targetClass.getValue(theValueField);
358
359        String vv = theValue.value();
360        String rv = ((StringReference)retValue).value();
361        if (vv != rv) {
362            failure("failure: String: expected " + vv + ", got " + rv);
363        } else {
364            System.out.println("Passed: String: " + rv);
365            successes++;
366        }
367    }
368
369    void ckClassValue(Value retValue) {
370        Field theValueField = targetClass.fieldByName("classValue");
371        ClassObjectReference vv = (ClassObjectReference)targetClass.
372            getValue(theValueField);
373
374        ClassObjectReference rv = (ClassObjectReference)retValue;
375        if (vv != rv) {
376            failure("failure: Class: expected " + vv + ", got " + rv);
377        } else {
378            System.out.println("Passed: Class: " + rv);
379            successes++;
380        }
381    }
382
383    void ckClassLoaderValue(Value retValue) {
384        Field theValueField = targetClass.fieldByName("classLoaderValue");
385        ClassLoaderReference vv = (ClassLoaderReference)targetClass.
386            getValue(theValueField);
387
388        ClassLoaderReference rv = (ClassLoaderReference)retValue;
389        if (vv != rv) {
390            failure("failure: ClassLoader: expected " + vv + ", got " + rv);
391        } else {
392            System.out.println("Passed: ClassLoader: " + rv);
393            successes++;
394        }
395    }
396
397    void ckThreadValue(Value retValue) {
398        Field theValueField = targetClass.fieldByName("threadValue");
399        ThreadReference vv = (ThreadReference)targetClass.
400            getValue(theValueField);
401
402        ThreadReference rv = (ThreadReference)retValue;
403        if (vv != rv) {
404            failure("failure: Thread: expected " + vv + ", got " + rv);
405        } else {
406            System.out.println("Passed: Thread: " + rv);
407            successes++;
408        }
409    }
410
411    void ckThreadGroupValue(Value retValue) {
412        Field theValueField = targetClass.fieldByName("threadGroupValue");
413        ThreadGroupReference vv = (ThreadGroupReference)targetClass.
414            getValue(theValueField);
415
416        ThreadGroupReference rv = (ThreadGroupReference)retValue;
417        if (vv != rv) {
418            failure("failure: ThreadgGroup: expected " + vv + ", got " + rv);
419        } else {
420            System.out.println("Passed: ThreadGroup: " + rv);
421            successes++;
422        }
423    }
424
425    void ckArrayValue(Value retValue) {
426        Field theValueField = targetClass.fieldByName("intArrayValue");
427        ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField);
428        IntegerValue theElem2 = (IntegerValue)theValue.getValue(2);
429
430        ArrayReference theRetValue = (ArrayReference)retValue;
431        IntegerValue retElem2 = (IntegerValue)theRetValue.getValue(2);
432        int vv = theElem2.value();
433        int rv = retElem2.value();
434        if (vv != rv) {
435            failure("failure: in[2]: expected " + vv + ", got " + rv);
436        } else {
437            System.out.println("Passed: int[2]: " + rv);
438            successes++;
439        }
440    }
441
442    void ckNullObjectValue(Value retValue) {
443        if (retValue != null) {
444            failure("failure: NullObject: expected " + null + ", got " + retValue);
445        } else {
446            System.out.println("Passed: NullObject: " + retValue);
447            successes++;
448        }
449    }
450
451    void ckObjectValue(Value retValue) {
452        // We will check the ivar field which we know contains
453        // the value of 'stringValue'
454        Field theValueField = targetClass.fieldByName("stringValue");
455        StringReference theValue = (StringReference)targetClass.getValue(theValueField);
456
457        Field theIVarField = targetClass.fieldByName("ivar");
458        ObjectReference theRetValue = (ObjectReference)retValue;
459        StringReference theRetValField = (StringReference)theRetValue.getValue(theIVarField);
460
461        String vv = theValue.value();
462        String rv = theRetValField.value();
463        if (vv != rv) {
464            failure("failure: Object: expected " + vv + ", got " + rv);
465       } else {
466            System.out.println("Passed: Object: " + rv);
467            successes++;
468        }
469    }
470
471    void ckVoidValue(Value retValue) {
472        System.out.println("Passed: Void");
473        successes++;
474    }
475
476    void ckSinValue(Value retValue) {
477        double rv = ((DoubleValue)retValue).value();
478        double vv = StrictMath.sin(MethodExitReturnValuesTarg.doubleValue);
479        if (rv != vv) {
480            failure("failure: sin: expected " + vv + ", got " + rv);
481        } else {
482            System.out.println("Passed: sin " + rv);
483            successes++;
484        }
485    }
486
487    // This is the MethodExitEvent handler.
488    public void methodExited(MethodExitEvent event) {
489        String origMethodName = event.method().name();
490        if (vmm.majorInterfaceVersion() >= 1 &&
491            vmm.minorInterfaceVersion() >= 6 &&
492            vm().canGetMethodReturnValues()) {
493            Value retValue = event.returnValue();
494
495            if ("sin".equals(origMethodName)) {
496                ckSinValue(retValue);
497                return;
498            }
499
500            if (!origMethodName.startsWith("s_") &&
501                !origMethodName.startsWith("i_")) {
502                // Check native methods
503                if ("getByte".equals(origMethodName))         ckByteValue(retValue);
504                else if ("getChar".equals(origMethodName))    ckCharValue(retValue);
505                else if ("getDouble".equals(origMethodName))  ckDoubleValue(retValue);
506                else if ("getFloat".equals(origMethodName))   ckFloatValue(retValue);
507                else if ("getInt".equals(origMethodName))     ckIntValue(retValue);
508                else if ("getLong".equals(origMethodName))    ckLongValue(retValue);
509                else if ("getShort".equals(origMethodName))   ckShortValue(retValue);
510                else if ("getBoolean".equals(origMethodName)) ckBooleanValue(retValue);
511                else if ("getObject".equals(origMethodName))  ckObjectValue(retValue);
512                else if ("intern".equals(origMethodName))     ckStringValue(retValue);
513                return;
514            }
515
516            String methodName = origMethodName.substring(2);
517            if ("show".equals(methodName)) {
518                System.out.println(retValue);
519                return;
520            }
521
522            if ("bytef".equals(methodName))             ckByteValue(retValue);
523            else if ("charf".equals(methodName))        ckCharValue(retValue);
524            else if ("doublef".equals(methodName))      ckDoubleValue(retValue);
525            else if ("floatf".equals(methodName))       ckFloatValue(retValue);
526            else if ("intf".equals(methodName))         ckIntValue(retValue);
527            else if ("longf".equals(methodName))        ckLongValue(retValue);
528            else if ("shortf".equals(methodName))       ckShortValue(retValue);
529            else if ("booleanf".equals(methodName))     ckBooleanValue(retValue);
530            else if ("stringf".equals(methodName))      ckStringValue(retValue);
531            else if ("classf".equals(methodName))       ckClassValue(retValue);
532            else if ("classLoaderf".equals(methodName)) ckClassLoaderValue(retValue);
533            else if ("threadf".equals(methodName))      ckThreadValue(retValue);
534            else if ("threadGroupf".equals(methodName)) ckThreadGroupValue(retValue);
535            else if ("intArrayf".equals(methodName))    ckArrayValue(retValue);
536            else if ("nullObjectf".equals(methodName))  ckNullObjectValue(retValue);
537            else if ("objectf".equals(methodName))      ckObjectValue(retValue);
538            else if ("voidf".equals(methodName))        ckVoidValue(retValue);
539            else {
540                failure("failure: Unknown methodName: " + origMethodName);
541            }
542        } else {
543            System.out.println("Return Value not available for method: " + origMethodName);
544        }
545    }
546
547    protected void runTests() throws Exception {
548        /*
549         * Get to the top of main()
550         * to determine targetClass and mainThread
551         */
552        BreakpointEvent bpe = startToMain("MethodExitReturnValuesTarg");
553        targetClass = (ClassType)bpe.location().declaringType();
554        mainThread = bpe.thread();
555
556        theValueField = targetClass.fieldByName("theValue");
557
558        /*
559         * Ask for method exit events
560         */
561        MethodExitRequest exitRequest =
562            eventRequestManager().createMethodExitRequest();
563
564        for (int i=0; i<excludes.length; ++i) {
565            exitRequest.addClassExclusionFilter(excludes[i]);
566        }
567        int sessionSuspendPolicy = EventRequest.SUSPEND_ALL;
568        //sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
569        //sessionSuspendPolicy = EventRequest.SUSPEND_NONE;
570        exitRequest.setSuspendPolicy(sessionSuspendPolicy);
571        exitRequest.enable();
572
573        /*
574         * We are now set up to receive the notifications we want.
575         * Here we go.  This adds 'this' as a listener so
576         * that our handlers above will be called.
577         */
578
579        listenUntilVMDisconnect();
580
581        if (successes != expectedSuccesses) {
582            failure("failure: Expected " + expectedSuccesses + ", but got " + successes);
583        }
584        System.out.println("All done, " + successes + " passed");
585
586
587        if (!testFailed) {
588            System.out.println();
589            System.out.println("MethodExitReturnValuesTest: passed");
590        } else {
591            System.out.println();
592            System.out.println("MethodExitReturnValuesTest: failed");
593            throw new Exception("MethodExitReturnValuesTest: failed");
594        }
595    }
596}
597