EarlyReturnNegativeTest.java revision 11884:b45c81ca8671
1/*
2 * Copyright (c) 2006, 2015, 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 6431735
27 *  @summary Unexpected ClassCastException in ThreadReference.forceEarlyReturn
28 *  @author Jim Holmlund
29 *
30 *  @modules jdk.jdi
31 *  @run build TestScaffold VMConnection TargetListener TargetAdapter
32 *  @run compile -g EarlyReturnNegativeTest.java
33 *  @run driver EarlyReturnNegativeTest
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 an instance method
45 * for each kind of JDI value return type.
46 *
47 * The debugger sets breakpoints in all methods.  When a breakpoint
48 * is hit the debugger requests an early return and supplies a new
49 * return value. The new value is not compatible with the method's
50 * return type so an InvalidTypeException should be thrown.
51 *
52 * Each value is stored in a static var in the debuggee.  The debugger
53 * gets the values from these static vars to pass back to the
54 * debuggee in forceEarlyReturn.
55 *
56 * This test was created out of EarlyReturnTest.java.  Not all of the
57 * debuggee methods are actually used, just the ones needed to test
58 * for correct operation.  I left the others in just in case they come
59 * in handy in the future.
60 */
61
62class EarlyReturnNegativeTarg {
63    /*
64     * These are the values that will be used by methods
65     * returning normally.
66     */
67    static URL[] urls = new URL[1];
68    public static byte      byteValue = 89;
69    public static char      charValue = 'x';
70    public static double    doubleValue = 2.2;
71    public static float     floatValue = 3.3f;
72    public static int       intValue = 1;
73    public static long      longValue = Long.MAX_VALUE;
74    public static short     shortValue = 8;
75    public static boolean   booleanValue = false;
76
77    public static Class       classValue = Object.class;
78    public static ClassLoader classLoaderValue;
79    {
80        try {
81            urls[0] = new URL("hi there");
82        } catch (java.net.MalformedURLException ee) {
83        }
84        classLoaderValue = new URLClassLoader(urls);
85    }
86
87    public static Thread      threadValue = Thread.currentThread();
88    public static ThreadGroup threadGroupValue = threadValue.getThreadGroup();
89    public static String      stringValue = "abc";
90    public static int[]       intArrayValue = new int[] {1, 2, 3};
91    public static Object[]    objectArrayValue = new Object[] {"a", "b", "c"};
92
93    public static EarlyReturnNegativeTarg  objectValue =
94        new EarlyReturnNegativeTarg();
95    public String ivar = stringValue;
96
97
98    // Used to show which set of tests follows
99    public static String s_show(String p1) { return p1;}
100
101    // These are the instance methods
102    public byte i_bytef()            { return byteValue; }
103    public char i_charf()            { return charValue; }
104    public double i_doublef()        { return doubleValue; }
105    public float i_floatf()          { return floatValue; }
106    public int i_intf()              { return intValue; }
107    public long i_longf()            { return longValue; }
108    public short i_shortf()          { return shortValue; }
109    public boolean i_booleanf()      { return booleanValue; }
110    public String i_stringf()        { return stringValue; }
111    public Class i_classf()          { return classValue; }
112    public ClassLoader i_classLoaderf()
113                                     { return classLoaderValue; }
114    public Thread i_threadf()        { return threadValue; }
115    public ThreadGroup i_threadGroupf()
116                                     { return threadGroupValue; }
117    public int[] i_intArrayf()       { return intArrayValue; }
118    public Object[] i_objectArrayf() { return objectArrayValue; }
119    public Object i_nullObjectf()    { return null; }
120    public Object i_objectf()        { return objectValue; }
121    public void i_voidf()            {}
122
123    static void doit(EarlyReturnNegativeTarg xx) throws Exception {
124        System.err.print("debugee in doit ");
125
126        s_show("==========  Testing instance methods ================");
127        xx.i_bytef();
128        xx.i_charf();
129        xx.i_doublef();
130        xx.i_floatf();
131        xx.i_intf();
132        xx.i_longf();
133        xx.i_shortf();
134        xx.i_booleanf();
135        xx.i_stringf();
136        xx.i_intArrayf();
137        xx.i_objectArrayf();
138        xx.i_classf();
139        xx.i_classLoaderf();
140        xx.i_threadf();
141        xx.i_threadGroupf();
142        xx.i_nullObjectf();
143        xx.i_objectf();
144        xx.i_voidf();
145
146    }
147
148    public static void main(String[] args) throws Exception {
149        /*
150         * The debugger will stop at the start of main,
151         * set breakpoints and then do a resume.
152         */
153        System.err.println("debugee in main");
154
155        EarlyReturnNegativeTarg xx =
156            new EarlyReturnNegativeTarg();
157
158        doit(xx);
159    }
160}
161
162
163
164public class EarlyReturnNegativeTest extends TestScaffold {
165
166    static VirtualMachineManager vmm ;
167    ClassType targetClass;
168    Field theValueField;
169
170    ByteValue byteVV;
171    CharValue charVV;
172    DoubleValue doubleVV;
173    FloatValue floatVV;
174    IntegerValue integerVV;
175    LongValue longVV;
176    ShortValue shortVV;
177    BooleanValue booleanVV;
178    ObjectReference objectVV;
179    ArrayReference intArrayVV;
180    ArrayReference objectArrayVV;
181    VoidValue voidVV;
182
183    EarlyReturnNegativeTest(String args[]) {
184        super(args);
185    }
186
187    public static void main(String[] args)      throws Exception {
188        EarlyReturnNegativeTest meee = new EarlyReturnNegativeTest(args);
189        vmm = Bootstrap.virtualMachineManager();
190        meee.startTests();
191    }
192
193    public BreakpointRequest setBreakpoint(String clsName,
194                                           String methodName,
195                                           String methodSignature) {
196        ReferenceType rt = findReferenceType(clsName);
197        if (rt == null) {
198            rt = resumeToPrepareOf(clsName).referenceType();
199        }
200
201        Method method = findMethod(rt, methodName, methodSignature);
202        if (method == null) {
203            throw new IllegalArgumentException("Bad method name/signature");
204        }
205        BreakpointRequest bpr = eventRequestManager().createBreakpointRequest(method.location());
206        bpr.setSuspendPolicy(EventRequest.SUSPEND_ALL);
207        bpr.enable();
208        return bpr;
209    }
210
211    void doEarly(ThreadReference tr, String methodName, Value val) {
212        try {
213            tr.forceEarlyReturn(val);
214        } catch (InvalidTypeException ex) {
215            System.out.println("Ok: " + methodName);
216            return;
217        } catch (Exception ex) {
218            failure("failure: " + ex.toString());
219            ex.printStackTrace();
220            return;
221        }
222        failure("Expected InvalidTypeException for " + methodName + ", " + val + " but didn't get it.");
223    }
224
225    public void breakpointReached(BreakpointEvent event) {
226        String origMethodName = event.location().method().name();
227        String methodName = origMethodName.substring(2);
228        ThreadReference tr = event.thread();
229
230        if (vmm.majorInterfaceVersion() >= 1 &&
231            vmm.minorInterfaceVersion() >= 6 &&
232            vm().canForceEarlyReturn()) {
233
234            /* There are some incompatible classes of values.  In the following,
235             * we test each combination.
236             */
237            if ("shortf".equals(methodName)){
238                doEarly(tr, origMethodName, booleanVV);
239                doEarly(tr, origMethodName, objectVV);
240                doEarly(tr, origMethodName, voidVV);
241                doEarly(tr, origMethodName, intArrayVV);
242                doEarly(tr, origMethodName, objectArrayVV);
243
244            } else if ("booleanf".equals(methodName)) {
245                doEarly(tr, origMethodName, shortVV);
246                doEarly(tr, origMethodName, objectVV);
247                doEarly(tr, origMethodName, voidVV);
248                doEarly(tr, origMethodName, intArrayVV);
249                doEarly(tr, origMethodName, objectArrayVV);
250
251            } else if ("intArrayf".equals(methodName)) {
252                doEarly(tr, origMethodName, booleanVV);
253                doEarly(tr, origMethodName, shortVV);
254                doEarly(tr, origMethodName, voidVV);
255                doEarly(tr, origMethodName, objectVV);
256                doEarly(tr, origMethodName, objectArrayVV);
257
258            } else if ("objectArrayf".equals(methodName)) {
259                doEarly(tr, origMethodName, booleanVV);
260                doEarly(tr, origMethodName, shortVV);
261                doEarly(tr, origMethodName, voidVV);
262                doEarly(tr, origMethodName, objectVV);
263                doEarly(tr, origMethodName, intArrayVV);
264
265            } else if ("objectf".equals(methodName)) {
266                doEarly(tr, origMethodName, booleanVV);
267                doEarly(tr, origMethodName, shortVV);
268                doEarly(tr, origMethodName, voidVV);
269
270             } else if ("voidf".equals(methodName)) {
271                doEarly(tr, origMethodName, booleanVV);
272                doEarly(tr, origMethodName, shortVV);
273                doEarly(tr, origMethodName, objectVV);
274                doEarly(tr, origMethodName, intArrayVV);
275                doEarly(tr, origMethodName, objectArrayVV);
276
277            } else {
278                // just ignore others
279                System.out.println("Ignoring: " + methodName);
280                return;
281            }
282        } else {
283            System.out.println("Cannot force early return for method: " + origMethodName);
284        }
285    }
286
287    protected void runTests() throws Exception {
288        /*
289         * Get to the top of main()
290         * to determine targetClass and mainThread
291         */
292
293        BreakpointEvent bpe = startToMain("EarlyReturnNegativeTarg");
294        targetClass = (ClassType)bpe.location().declaringType();
295        mainThread = bpe.thread();
296
297        /*
298         * We set and enable breakpoints on all of the interesting
299         * methods called by doit().  In the breakpointReached()
300         * handler we force an early return with a different return
301         * value.
302         *
303         */
304
305        setBreakpoint("EarlyReturnNegativeTarg", "i_bytef", "()B");
306        setBreakpoint("EarlyReturnNegativeTarg", "i_charf", "()C");
307        setBreakpoint("EarlyReturnNegativeTarg", "i_doublef", "()D");
308        setBreakpoint("EarlyReturnNegativeTarg", "i_floatf", "()F");
309        setBreakpoint("EarlyReturnNegativeTarg", "i_intf", "()I");
310        setBreakpoint("EarlyReturnNegativeTarg", "i_longf", "()J");
311        setBreakpoint("EarlyReturnNegativeTarg", "i_shortf", "()S");
312        setBreakpoint("EarlyReturnNegativeTarg", "i_booleanf", "()Z");
313        setBreakpoint("EarlyReturnNegativeTarg", "i_stringf", "()Ljava/lang/String;");
314        setBreakpoint("EarlyReturnNegativeTarg", "i_intArrayf", "()[I");
315        setBreakpoint("EarlyReturnNegativeTarg", "i_objectArrayf", "()[Ljava/lang/Object;");
316        setBreakpoint("EarlyReturnNegativeTarg", "i_classf", "()Ljava/lang/Class;");
317        setBreakpoint("EarlyReturnNegativeTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;");
318        setBreakpoint("EarlyReturnNegativeTarg", "i_threadf", "()Ljava/lang/Thread;");
319        setBreakpoint("EarlyReturnNegativeTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;");
320        setBreakpoint("EarlyReturnNegativeTarg", "i_nullObjectf", "()Ljava/lang/Object;");
321        setBreakpoint("EarlyReturnNegativeTarg", "i_objectf", "()Ljava/lang/Object;");
322        setBreakpoint("EarlyReturnNegativeTarg", "i_voidf", "()V");
323
324        /* Create Value objects to be passed in forceEarlyReturn calls */
325        Field theValueField = targetClass.fieldByName("byteValue");
326        byteVV = (ByteValue)targetClass.getValue(theValueField);
327
328        theValueField = targetClass.fieldByName("charValue");
329        charVV = (CharValue)targetClass.getValue(theValueField);
330
331        theValueField = targetClass.fieldByName("doubleValue");
332        doubleVV = (DoubleValue)targetClass.getValue(theValueField);
333
334        theValueField = targetClass.fieldByName("floatValue");
335        floatVV = (FloatValue)targetClass.getValue(theValueField);
336
337        theValueField = targetClass.fieldByName("intValue");
338        integerVV = (IntegerValue)targetClass.getValue(theValueField);
339
340        theValueField = targetClass.fieldByName("longValue");
341        longVV = (LongValue)targetClass.getValue(theValueField);
342
343        theValueField = targetClass.fieldByName("shortValue");
344        shortVV = (ShortValue)targetClass.getValue(theValueField);
345
346        theValueField = targetClass.fieldByName("booleanValue");
347        booleanVV = (BooleanValue)targetClass.getValue(theValueField);
348
349        theValueField = targetClass.fieldByName("objectValue");
350        objectVV = (ObjectReference)targetClass.getValue(theValueField);
351
352        theValueField = targetClass.fieldByName("intArrayValue");
353        intArrayVV = (ArrayReference)targetClass.getValue(theValueField);
354
355        theValueField = targetClass.fieldByName("objectArrayValue");
356        objectArrayVV = (ArrayReference)targetClass.getValue(theValueField);
357
358        voidVV = vm().mirrorOfVoid();
359
360        /* Here we go.  This adds 'this' as a listener so
361         * that our handlers above will be called.
362         */
363        listenUntilVMDisconnect();
364
365        if (!testFailed) {
366            System.out.println();
367            System.out.println("EarlyReturnNegativeTest: passed");
368        } else {
369            System.out.println();
370            System.out.println("EarlyReturnNegativeTest: failed");
371            throw new Exception("EarlyReturnNegativeTest: failed");
372        }
373    }
374}
375