jdk/test/com/sun/jdi/EarlyReturnNegativeTest.java
author ohair
Tue, 28 Dec 2010 15:53:50 -0800
changeset 7668 d4a77089c587
parent 5506 202f599c92aa
child 24973 8c4bc3fa4c4e
permissions -rw-r--r--
6962318: Update copyright year Reviewed-by: xdono

/*
 * Copyright (c) 2006, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.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");
        }
    }
}