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