jdk/test/com/sun/jdi/EarlyReturnNegativeTest.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/EarlyReturnNegativeTest.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ *  @test
+ *  @bug 6431735
+ *  @summary Unexpected ClassCastException in ThreadReference.forceEarlyReturn
+ *  @author Jim Holmlund
+ *
+ *  @run build TestScaffold VMConnection TargetListener TargetAdapter
+ *  @run compile -g EarlyReturnNegativeTest.java
+ *  @run main EarlyReturnNegativeTest
+ */
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import java.util.*;
+import java.net.URLClassLoader;
+import java.net.URL;
+import java.lang.reflect.Array;
+
+/*
+ * This test has a debuggee which calls an instance method
+ * for each kind of JDI value return type.
+ *
+ * The debugger sets breakpoints in all methods.  When a breakpoint
+ * is hit the debugger requests an early return and supplies a new
+ * return value. The new value is not compatible with the method's
+ * return type so an InvalidTypeException should be thrown.
+ *
+ * Each value is stored in a static var in the debuggee.  The debugger
+ * gets the values from these static vars to pass back to the
+ * debuggee in forceEarlyReturn.
+ *
+ * This test was created out of EarlyReturnTest.java.  Not all of the
+ * debuggee methods are actually used, just the ones needed to test
+ * for correct operation.  I left the others in just in case they come
+ * in handy in the future.
+ */
+
+class EarlyReturnNegativeTarg {
+    /*
+     * These are the values that will be used by methods
+     * returning normally.
+     */
+    static URL[] urls = new URL[1];
+    public static byte      byteValue = 89;
+    public static char      charValue = 'x';
+    public static double    doubleValue = 2.2;
+    public static float     floatValue = 3.3f;
+    public static int       intValue = 1;
+    public static long      longValue = Long.MAX_VALUE;
+    public static short     shortValue = 8;
+    public static boolean   booleanValue = false;
+
+    public static Class       classValue = Object.class;
+    public static ClassLoader classLoaderValue;
+    {
+        try {
+            urls[0] = new URL("hi there");
+        } catch (java.net.MalformedURLException ee) {
+        }
+        classLoaderValue = new URLClassLoader(urls);
+    }
+
+    public static Thread      threadValue = Thread.currentThread();
+    public static ThreadGroup threadGroupValue = threadValue.getThreadGroup();
+    public static String      stringValue = "abc";
+    public static int[]       intArrayValue = new int[] {1, 2, 3};
+    public static Object[]    objectArrayValue = new Object[] {"a", "b", "c"};
+
+    public static EarlyReturnNegativeTarg  objectValue =
+        new EarlyReturnNegativeTarg();
+    public String ivar = stringValue;
+
+
+    // Used to show which set of tests follows
+    public static String s_show(String p1) { return p1;}
+
+    // These are the instance methods
+    public byte i_bytef()            { return byteValue; }
+    public char i_charf()            { return charValue; }
+    public double i_doublef()        { return doubleValue; }
+    public float i_floatf()          { return floatValue; }
+    public int i_intf()              { return intValue; }
+    public long i_longf()            { return longValue; }
+    public short i_shortf()          { return shortValue; }
+    public boolean i_booleanf()      { return booleanValue; }
+    public String i_stringf()        { return stringValue; }
+    public Class i_classf()          { return classValue; }
+    public ClassLoader i_classLoaderf()
+                                     { return classLoaderValue; }
+    public Thread i_threadf()        { return threadValue; }
+    public ThreadGroup i_threadGroupf()
+                                     { return threadGroupValue; }
+    public int[] i_intArrayf()       { return intArrayValue; }
+    public Object[] i_objectArrayf() { return objectArrayValue; }
+    public Object i_nullObjectf()    { return null; }
+    public Object i_objectf()        { return objectValue; }
+    public void i_voidf()            {}
+
+    static void doit(EarlyReturnNegativeTarg xx) throws Exception {
+        System.err.print("debugee in doit ");
+
+        s_show("==========  Testing instance methods ================");
+        xx.i_bytef();
+        xx.i_charf();
+        xx.i_doublef();
+        xx.i_floatf();
+        xx.i_intf();
+        xx.i_longf();
+        xx.i_shortf();
+        xx.i_booleanf();
+        xx.i_stringf();
+        xx.i_intArrayf();
+        xx.i_objectArrayf();
+        xx.i_classf();
+        xx.i_classLoaderf();
+        xx.i_threadf();
+        xx.i_threadGroupf();
+        xx.i_nullObjectf();
+        xx.i_objectf();
+        xx.i_voidf();
+
+    }
+
+    public static void main(String[] args) throws Exception {
+        /*
+         * The debugger will stop at the start of main,
+         * set breakpoints and then do a resume.
+         */
+        System.err.println("debugee in main");
+
+        EarlyReturnNegativeTarg xx =
+            new EarlyReturnNegativeTarg();
+
+        doit(xx);
+    }
+}
+
+
+
+public class EarlyReturnNegativeTest extends TestScaffold {
+
+    static VirtualMachineManager vmm ;
+    ClassType targetClass;
+    Field theValueField;
+
+    ByteValue byteVV;
+    CharValue charVV;
+    DoubleValue doubleVV;
+    FloatValue floatVV;
+    IntegerValue integerVV;
+    LongValue longVV;
+    ShortValue shortVV;
+    BooleanValue booleanVV;
+    ObjectReference objectVV;
+    ArrayReference intArrayVV;
+    ArrayReference objectArrayVV;
+    VoidValue voidVV;
+
+    EarlyReturnNegativeTest(String args[]) {
+        super(args);
+    }
+
+    public static void main(String[] args)      throws Exception {
+        EarlyReturnNegativeTest meee = new EarlyReturnNegativeTest(args);
+        vmm = Bootstrap.virtualMachineManager();
+        meee.startTests();
+    }
+
+    public BreakpointRequest setBreakpoint(String clsName,
+                                           String methodName,
+                                           String methodSignature) {
+        ReferenceType rt = findReferenceType(clsName);
+        if (rt == null) {
+            rt = resumeToPrepareOf(clsName).referenceType();
+        }
+
+        Method method = findMethod(rt, methodName, methodSignature);
+        if (method == null) {
+            throw new IllegalArgumentException("Bad method name/signature");
+        }
+        BreakpointRequest bpr = eventRequestManager().createBreakpointRequest(method.location());
+        bpr.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+        bpr.enable();
+        return bpr;
+    }
+
+    void doEarly(ThreadReference tr, String methodName, Value val) {
+        try {
+            tr.forceEarlyReturn(val);
+        } catch (InvalidTypeException ex) {
+            System.out.println("Ok: " + methodName);
+            return;
+        } catch (Exception ex) {
+            failure("failure: " + ex.toString());
+            ex.printStackTrace();
+            return;
+        }
+        failure("Expected InvalidTypeException for " + methodName + ", " + val + " but didn't get it.");
+    }
+
+    public void breakpointReached(BreakpointEvent event) {
+        String origMethodName = event.location().method().name();
+        String methodName = origMethodName.substring(2);
+        ThreadReference tr = event.thread();
+
+        if (vmm.majorInterfaceVersion() >= 1 &&
+            vmm.minorInterfaceVersion() >= 6 &&
+            vm().canForceEarlyReturn()) {
+
+            /* There are some incompatible classes of values.  In the following,
+             * we test each combination.
+             */
+            if ("shortf".equals(methodName)){
+                doEarly(tr, origMethodName, booleanVV);
+                doEarly(tr, origMethodName, objectVV);
+                doEarly(tr, origMethodName, voidVV);
+                doEarly(tr, origMethodName, intArrayVV);
+                doEarly(tr, origMethodName, objectArrayVV);
+
+            } else if ("booleanf".equals(methodName)) {
+                doEarly(tr, origMethodName, shortVV);
+                doEarly(tr, origMethodName, objectVV);
+                doEarly(tr, origMethodName, voidVV);
+                doEarly(tr, origMethodName, intArrayVV);
+                doEarly(tr, origMethodName, objectArrayVV);
+
+            } else if ("intArrayf".equals(methodName)) {
+                doEarly(tr, origMethodName, booleanVV);
+                doEarly(tr, origMethodName, shortVV);
+                doEarly(tr, origMethodName, voidVV);
+                doEarly(tr, origMethodName, objectVV);
+                doEarly(tr, origMethodName, objectArrayVV);
+
+            } else if ("objectArrayf".equals(methodName)) {
+                doEarly(tr, origMethodName, booleanVV);
+                doEarly(tr, origMethodName, shortVV);
+                doEarly(tr, origMethodName, voidVV);
+                doEarly(tr, origMethodName, objectVV);
+                doEarly(tr, origMethodName, intArrayVV);
+
+            } else if ("objectf".equals(methodName)) {
+                doEarly(tr, origMethodName, booleanVV);
+                doEarly(tr, origMethodName, shortVV);
+                doEarly(tr, origMethodName, voidVV);
+
+             } else if ("voidf".equals(methodName)) {
+                doEarly(tr, origMethodName, booleanVV);
+                doEarly(tr, origMethodName, shortVV);
+                doEarly(tr, origMethodName, objectVV);
+                doEarly(tr, origMethodName, intArrayVV);
+                doEarly(tr, origMethodName, objectArrayVV);
+
+            } else {
+                // just ignore others
+                System.out.println("Ignoring: " + methodName);
+                return;
+            }
+        } else {
+            System.out.println("Cannot force early return for method: " + origMethodName);
+        }
+    }
+
+    protected void runTests() throws Exception {
+        /*
+         * Get to the top of main()
+         * to determine targetClass and mainThread
+         */
+
+        BreakpointEvent bpe = startToMain("EarlyReturnNegativeTarg");
+        targetClass = (ClassType)bpe.location().declaringType();
+        mainThread = bpe.thread();
+
+        /*
+         * We set and enable breakpoints on all of the interesting
+         * methods called by doit().  In the breakpointReached()
+         * handler we force an early return with a different return
+         * value.
+         *
+         */
+
+        setBreakpoint("EarlyReturnNegativeTarg", "i_bytef", "()B");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_charf", "()C");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_doublef", "()D");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_floatf", "()F");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_intf", "()I");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_longf", "()J");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_shortf", "()S");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_booleanf", "()Z");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_stringf", "()Ljava/lang/String;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_intArrayf", "()[I");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_objectArrayf", "()[Ljava/lang/Object;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_classf", "()Ljava/lang/Class;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_threadf", "()Ljava/lang/Thread;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_nullObjectf", "()Ljava/lang/Object;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_objectf", "()Ljava/lang/Object;");
+        setBreakpoint("EarlyReturnNegativeTarg", "i_voidf", "()V");
+
+        /* Create Value objects to be passed in forceEarlyReturn calls */
+        Field theValueField = targetClass.fieldByName("byteValue");
+        byteVV = (ByteValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("charValue");
+        charVV = (CharValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("doubleValue");
+        doubleVV = (DoubleValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("floatValue");
+        floatVV = (FloatValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("intValue");
+        integerVV = (IntegerValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("longValue");
+        longVV = (LongValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("shortValue");
+        shortVV = (ShortValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("booleanValue");
+        booleanVV = (BooleanValue)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("objectValue");
+        objectVV = (ObjectReference)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("intArrayValue");
+        intArrayVV = (ArrayReference)targetClass.getValue(theValueField);
+
+        theValueField = targetClass.fieldByName("objectArrayValue");
+        objectArrayVV = (ArrayReference)targetClass.getValue(theValueField);
+
+        voidVV = vm().mirrorOfVoid();
+
+        /* Here we go.  This adds 'this' as a listener so
+         * that our handlers above will be called.
+         */
+        listenUntilVMDisconnect();
+
+        if (!testFailed) {
+            System.out.println();
+            System.out.println("EarlyReturnNegativeTest: passed");
+        } else {
+            System.out.println();
+            System.out.println("EarlyReturnNegativeTest: failed");
+            throw new Exception("EarlyReturnNegativeTest: failed");
+        }
+    }
+}