| /* |
| * Copyright (c) 2005, 2016, 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 6175634 |
| * @summary Allow early return from methods |
| * |
| * @bug 6431720 |
| * @summary Unexpected InvalidTypeException when call ThreadReference.forceEarlyReturn with VoidValue |
| * |
| * @bug 6432855 |
| * @summary Need a way to create JDI VoidValue for use in ThreadReference.forceEarlyReturn |
| * |
| * @author Tim Bell (based on MethodExitReturnValuesTest by Jim Holmlund) |
| * |
| * @run build TestScaffold VMConnection TargetListener TargetAdapter |
| * @run compile -g EarlyReturnTest.java |
| * @run driver EarlyReturnTest |
| */ |
| 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 a static method |
| * for each kind of JDI Value, and then an instance method |
| * for each. |
| * |
| * The debugger sets breakpoints in all methods. When a breakpoint |
| * is hit the debugger requests an early return and supplies a new |
| * return value. It then checks that the correct return values are |
| * included in the MethodExitEvents. |
| * |
| * Each value is stored in a static var in the debuggee. The debugger |
| * gets the values from these static vars to check for correct |
| * return values in the MethodExitEvents. |
| */ |
| |
| class EarlyReturnTarg { |
| static boolean debuggerWatching = false; |
| static int failureCount = 0; |
| /* |
| * 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 EarlyReturnTarg objectValue = |
| new EarlyReturnTarg(); |
| public String ivar = stringValue; |
| |
| /* |
| * These are the values that will be used by methods |
| * returning early. These are != the normal values |
| * defined above. |
| */ |
| static URL[] eurls = new URL[1]; |
| public static byte ebyteValue = 42; |
| public static char echarValue = 'a'; |
| public static double edoubleValue = 6.6; |
| public static float efloatValue = 9.9f; |
| public static int eintValue = 7; |
| public static long elongValue = Long.MIN_VALUE; |
| public static short eshortValue = 3; |
| public static boolean ebooleanValue = true; |
| |
| public static Class eclassValue = String.class; |
| public static ClassLoader eclassLoaderValue; |
| { |
| try { |
| urls[0] = new URL("been there, done that"); |
| } catch (java.net.MalformedURLException ee) { |
| } |
| classLoaderValue = new URLClassLoader(urls); |
| } |
| public static Thread ethreadValue; |
| public static ThreadGroup ethreadGroupValue; |
| public static String estringValue = "wxyz"; |
| public static int[] eintArrayValue = new int[] {10, 11, 12}; |
| |
| public static java.util.Date eobjectValue = new java.util.Date(); |
| |
| // Used to check the return values seen on the debugee side |
| public static boolean chk(byte v) { |
| return v == (debuggerWatching ? ebyteValue: byteValue); |
| } |
| public static boolean chk(char v) { |
| return v == (debuggerWatching ? echarValue: charValue); |
| } |
| public static boolean chk(double v) { |
| return v == (debuggerWatching ? edoubleValue: doubleValue); |
| } |
| public static boolean chk(float v) { |
| return v == (debuggerWatching ? efloatValue: floatValue); |
| } |
| public static boolean chk(int v) { |
| return v == (debuggerWatching ? eintValue: intValue); |
| } |
| public static boolean chk(long v) { |
| return v == (debuggerWatching ? elongValue: longValue); |
| } |
| public static boolean chk(short v) { |
| return v == (debuggerWatching ? eshortValue: shortValue); |
| } |
| public static boolean chk(boolean v) { |
| return v == (debuggerWatching ? ebooleanValue: booleanValue); |
| } |
| public static boolean chk(String v) { |
| return v.equals(debuggerWatching ? estringValue: stringValue); |
| } |
| public static boolean chk(Object v) { |
| return v.equals(debuggerWatching ? eobjectValue: objectValue); |
| } |
| |
| // Used to show which set of tests follows |
| public static String s_show(String p1) { return p1;} |
| |
| // These are the static methods |
| public static byte s_bytef(int p1){ return byteValue; } |
| public static char s_charf() { return charValue; } |
| public static double s_doublef() { return doubleValue; } |
| public static float s_floatf() { return floatValue; } |
| public static int s_intf() { return intValue; } |
| public static long s_longf() { return longValue; } |
| public static short s_shortf() { return shortValue; } |
| public static boolean s_booleanf(){ return booleanValue; } |
| public static String s_stringf() { return stringValue; } |
| public static Class s_classf() { return classValue; } |
| public static ClassLoader s_classLoaderf() |
| { return classLoaderValue; } |
| public static Thread s_threadf() { return threadValue; } |
| public static ThreadGroup s_threadGroupf() |
| { return threadGroupValue; } |
| public static int[] s_intArrayf() { return intArrayValue; } |
| public static Object s_nullObjectf() { return null; } |
| public static Object s_objectf() { return objectValue; } |
| public static void s_voidf() { System.err.println("debugee in s_voidf");} |
| |
| // These are the instance methods |
| public byte i_bytef(int p1) { 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_nullObjectf() { return null; } |
| public Object i_objectf() { return objectValue; } |
| public void i_voidf() {} |
| |
| static void doit(EarlyReturnTarg xx) throws Exception { |
| System.err.print("debugee in doit "); |
| if (debuggerWatching) { |
| System.err.println("with a debugger watching. Early returns expected."); |
| } else { |
| System.err.println("with no debugger watching. Normal returns."); |
| } |
| |
| s_show("========== Testing static methods ================"); |
| if (!chk( s_bytef(88))) failureCount++; |
| if (!chk( s_charf())) failureCount++; |
| if (!chk( s_doublef())) failureCount++; |
| if (!chk( s_floatf())) failureCount++; |
| if (!chk( s_intf())) failureCount++; |
| if (!chk( s_longf())) failureCount++; |
| if (!chk( s_shortf())) failureCount++; |
| if (!chk( s_booleanf())) failureCount++; |
| |
| if (!chk( s_stringf())) failureCount++; |
| s_classf(); |
| s_classLoaderf(); |
| s_threadf(); |
| s_threadGroupf(); |
| s_intArrayf(); |
| s_nullObjectf(); |
| if (!chk( s_objectf())) failureCount++; |
| s_voidf(); |
| |
| s_show("========== Testing instance methods ================"); |
| if (!chk( xx.i_bytef(89))) failureCount++; |
| if (!chk( xx.i_charf())) failureCount++; |
| if (!chk( xx.i_doublef())) failureCount++; |
| if (!chk( xx.i_floatf())) failureCount++; |
| if (!chk( xx.i_intf())) failureCount++; |
| if (!chk( xx.i_longf())) failureCount++; |
| if (!chk( xx.i_shortf())) failureCount++; |
| if (!chk( xx.i_booleanf())) failureCount++; |
| if (!chk( xx.i_stringf())) failureCount++; |
| xx.i_intArrayf(); |
| xx.i_classf(); |
| xx.i_classLoaderf(); |
| xx.i_threadf(); |
| xx.i_threadGroupf(); |
| xx.i_nullObjectf(); |
| if (!chk( xx.i_objectf())) failureCount++; |
| xx.i_voidf(); |
| |
| } |
| |
| /** Hang so that test fails */ |
| static void hang() { |
| try { |
| // ten minute nap |
| Thread.currentThread().sleep(10 * 60 * 1000); |
| } catch (InterruptedException exc) { |
| // shouldn't happen |
| } |
| } |
| |
| 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"); |
| EarlyReturnTarg xx = |
| new EarlyReturnTarg(); |
| |
| doit(xx); |
| if (debuggerWatching && failureCount > 0) { |
| hang(); |
| throw new Exception("EarlyReturnTarg: failed"); |
| } |
| } |
| } |
| |
| |
| |
| public class EarlyReturnTest extends TestScaffold { |
| |
| |
| /* |
| * Class patterns for which we don't want events (copied |
| * from the "Trace.java" example): |
| * http://java.sun.com/javase/technologies/core/toolsapis/jpda/ |
| */ |
| private String[] excludes = { |
| "javax.*", |
| "sun.*", |
| "com.sun.*", |
| "com.oracle.*", |
| "oracle.*"}; |
| |
| static VirtualMachineManager vmm ; |
| ClassType targetClass; |
| Field theValueField; |
| static int earlyReturns = 0; |
| static final int expectedEarlyReturns = 34; // determined by inspection :-) |
| |
| EarlyReturnTest(String args[]) { |
| super(args); |
| } |
| |
| public static void main(String[] args) throws Exception { |
| EarlyReturnTest meee = new EarlyReturnTest(args); |
| vmm = Bootstrap.virtualMachineManager(); |
| meee.startTests(); |
| } |
| |
| // chkXXX methods lifted directly from MethodExitReturnValuesTest |
| // These methods check for correct return values. Thanks, Jim! |
| void ckByteValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("ebyteValue"); |
| ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); |
| |
| byte vv = theValue.value(); |
| byte rv = ((ByteValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: byte: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: byte " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckCharValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("echarValue"); |
| CharValue theValue = (CharValue)targetClass.getValue(theValueField); |
| |
| char vv = theValue.value(); |
| char rv = ((CharValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: char: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: char " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckDoubleValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("edoubleValue"); |
| DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); |
| |
| double vv = theValue.value(); |
| double rv = ((DoubleValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: double: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: double " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckFloatValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("efloatValue"); |
| FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); |
| |
| float vv = theValue.value(); |
| float rv = ((FloatValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: float: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: float " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckIntValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("eintValue"); |
| IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); |
| |
| int vv = theValue.value(); |
| int rv = ((IntegerValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: int: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: int " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckLongValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("elongValue"); |
| LongValue theValue = (LongValue)targetClass.getValue(theValueField); |
| |
| long vv = theValue.value(); |
| long rv = ((LongValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: long: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: long " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckShortValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("eshortValue"); |
| ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); |
| |
| short vv = theValue.value(); |
| short rv = ((ShortValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: short: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: short " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckBooleanValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("ebooleanValue"); |
| BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); |
| |
| boolean vv = theValue.value(); |
| boolean rv = ((BooleanValue)retValue).value(); |
| if (vv != rv) { |
| failure("failure: boolean: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: boolean " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckStringValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("estringValue"); |
| StringReference theValue = (StringReference)targetClass.getValue(theValueField); |
| |
| String vv = theValue.value(); |
| String rv = ((StringReference)retValue).value(); |
| if (vv != rv) { |
| failure("failure: String: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: String: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckClassValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("eclassValue"); |
| ClassObjectReference vv = (ClassObjectReference)targetClass. |
| getValue(theValueField); |
| |
| ClassObjectReference rv = (ClassObjectReference)retValue; |
| if (vv != rv) { |
| failure("failure: Class: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: Class: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckClassLoaderValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("eclassLoaderValue"); |
| ClassLoaderReference vv = (ClassLoaderReference)targetClass. |
| getValue(theValueField); |
| |
| ClassLoaderReference rv = (ClassLoaderReference)retValue; |
| if (vv != rv) { |
| failure("failure: ClassLoader: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: ClassLoader: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckThreadValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("ethreadValue"); |
| ThreadReference vv = (ThreadReference)targetClass. |
| getValue(theValueField); |
| |
| ThreadReference rv = (ThreadReference)retValue; |
| if (vv != rv) { |
| failure("failure: Thread: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: Thread: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckThreadGroupValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("ethreadGroupValue"); |
| ThreadGroupReference vv = (ThreadGroupReference)targetClass. |
| getValue(theValueField); |
| |
| ThreadGroupReference rv = (ThreadGroupReference)retValue; |
| if (vv != rv) { |
| failure("failure: ThreadgGroup: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: ThreadGroup: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckArrayValue(Value retValue) { |
| Field theValueField = targetClass.fieldByName("eintArrayValue"); |
| ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); |
| IntegerValue theElem2 = (IntegerValue)theValue.getValue(2); |
| |
| ArrayReference theRetValue = (ArrayReference)retValue; |
| IntegerValue retElem2 = (IntegerValue)theRetValue.getValue(2); |
| int vv = theElem2.value(); |
| int rv = retElem2.value(); |
| if (vv != rv) { |
| failure("failure: in[2]: expected " + vv + ", got " + rv); |
| } else { |
| System.out.println("Passed: int[2]: " + rv); |
| earlyReturns++; |
| } |
| } |
| |
| void ckNullObjectValue(Value retValue) { |
| if (retValue != null) { |
| failure("failure: NullObject: expected " + null + ", got " + retValue); |
| } else { |
| System.out.println("Passed: NullObject: " + retValue); |
| earlyReturns++; |
| } |
| } |
| |
| void ckObjectValue(Value retValue) { |
| ObjectReference theRetValue = (ObjectReference)retValue; |
| |
| Field theIVarField = targetClass.fieldByName("eobjectValue"); |
| ObjectReference theRetValField = (ObjectReference)targetClass.getValue(theIVarField); |
| |
| if (! theRetValue.equals(theRetValField)) { |
| failure("failure: Object: expected " + theIVarField + ", got " + theRetValField); |
| } else { |
| System.out.println("Passed: Object: " + theRetValField); |
| earlyReturns++; |
| } |
| } |
| |
| void ckVoidValue(Value retValue) { |
| System.out.println("Passed: Void"); |
| earlyReturns++; |
| } |
| |
| 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; |
| } |
| |
| public void breakpointReached(BreakpointEvent event) { |
| String origMethodName = event.location().method().name(); |
| String methodName = origMethodName.substring(2); |
| ThreadReference tr = event.thread(); |
| |
| if (vm().canForceEarlyReturn()) { |
| |
| try { |
| |
| if ("bytef".equals(methodName)){ |
| Field theValueField = targetClass.fieldByName("ebyteValue"); |
| ByteValue theValue = (ByteValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| /* |
| * See what happens if we access the stack after the force |
| * and before the resume. Disabling this since spec says |
| * the stack is undefined. This type of code can be used to |
| * pursue just what that means. |
| * |
| * StackFrame sf = tr.frame(0); |
| * List<Value> ll = sf.getArgumentValues(); |
| * for (Value vv: ll) { |
| * System.out.println("vv = " + vv); |
| * } |
| */ |
| } else if ("charf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("echarValue"); |
| CharValue theValue = (CharValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("doublef".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("edoubleValue"); |
| DoubleValue theValue = (DoubleValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("floatf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("efloatValue"); |
| FloatValue theValue = (FloatValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("intf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eintValue"); |
| IntegerValue theValue = (IntegerValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("longf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("elongValue"); |
| LongValue theValue = (LongValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("shortf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eshortValue"); |
| ShortValue theValue = (ShortValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("booleanf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("ebooleanValue"); |
| BooleanValue theValue = (BooleanValue)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("stringf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("estringValue"); |
| StringReference theValue = (StringReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("classf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eclassValue"); |
| ClassObjectReference theValue = (ClassObjectReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("classLoaderf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eclassLoaderValue"); |
| ClassLoaderReference theValue = (ClassLoaderReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("threadf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("ethreadValue"); |
| ThreadReference theValue = (ThreadReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("threadGroupf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("ethreadGroupValue"); |
| ThreadGroupReference theValue = (ThreadGroupReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("intArrayf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eintArrayValue"); |
| ArrayReference theValue = (ArrayReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("nullObjectf".equals(methodName)) { |
| tr.forceEarlyReturn(null); |
| } else if ("objectf".equals(methodName)) { |
| Field theValueField = targetClass.fieldByName("eobjectValue"); |
| ObjectReference theValue = (ObjectReference)targetClass.getValue(theValueField); |
| tr.forceEarlyReturn(theValue); |
| } else if ("voidf".equals(methodName)) { |
| VoidValue theValue = vm().mirrorOfVoid(); |
| tr.forceEarlyReturn(theValue); |
| } else { |
| failure("failure: Unknown methodName: " + origMethodName); |
| } |
| |
| } catch (Exception ex) { |
| failure("failure: " + ex.toString()); |
| ex.printStackTrace(); |
| } |
| } else { |
| System.out.println("Cannot force early return for method: " + origMethodName); |
| } |
| } |
| |
| // This is the MethodExitEvent handler. |
| public void methodExited(MethodExitEvent event) { |
| String origMethodName = event.method().name(); |
| if (vm().canGetMethodReturnValues()) { |
| Value retValue = event.returnValue(); |
| |
| if (!origMethodName.startsWith("s_") && |
| !origMethodName.startsWith("i_")) { |
| // Skip all uninteresting methods |
| return; |
| } |
| |
| String methodName = origMethodName.substring(2); |
| if ("show".equals(methodName)) { |
| System.out.println(retValue); |
| return; |
| } |
| |
| if ("bytef".equals(methodName)) ckByteValue(retValue); |
| else if ("charf".equals(methodName)) ckCharValue(retValue); |
| else if ("doublef".equals(methodName)) ckDoubleValue(retValue); |
| else if ("floatf".equals(methodName)) ckFloatValue(retValue); |
| else if ("intf".equals(methodName)) ckIntValue(retValue); |
| else if ("longf".equals(methodName)) ckLongValue(retValue); |
| else if ("shortf".equals(methodName)) ckShortValue(retValue); |
| else if ("booleanf".equals(methodName)) ckBooleanValue(retValue); |
| else if ("stringf".equals(methodName)) ckStringValue(retValue); |
| else if ("classf".equals(methodName)) ckClassValue(retValue); |
| else if ("classLoaderf".equals(methodName)) ckClassLoaderValue(retValue); |
| else if ("threadf".equals(methodName)) ckThreadValue(retValue); |
| else if ("threadGroupf".equals(methodName)) ckThreadGroupValue(retValue); |
| else if ("intArrayf".equals(methodName)) ckArrayValue(retValue); |
| else if ("nullObjectf".equals(methodName)) ckNullObjectValue(retValue); |
| else if ("objectf".equals(methodName)) ckObjectValue(retValue); |
| else if ("voidf".equals(methodName)) ckVoidValue(retValue); |
| else { |
| failure("failure: Unknown methodName: " + origMethodName); |
| } |
| } else { |
| System.out.println("Return Value not available for method: " + origMethodName); |
| } |
| } |
| |
| protected void runTests() throws Exception { |
| /* |
| * Get to the top of main() |
| * to determine targetClass and mainThread |
| */ |
| |
| BreakpointEvent bpe = startToMain("EarlyReturnTarg"); |
| targetClass = (ClassType)bpe.location().declaringType(); |
| mainThread = bpe.thread(); |
| |
| /* |
| * Ask for method exit events |
| */ |
| MethodExitRequest exitRequest = |
| eventRequestManager().createMethodExitRequest(); |
| |
| for (int i=0; i<excludes.length; ++i) { |
| exitRequest.addClassExclusionFilter(excludes[i]); |
| } |
| int sessionSuspendPolicy = EventRequest.SUSPEND_ALL; |
| //sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; |
| //sessionSuspendPolicy = EventRequest.SUSPEND_NONE; |
| exitRequest.setSuspendPolicy(sessionSuspendPolicy); |
| exitRequest.enable(); |
| |
| /* |
| * Turn on the flag so debugee knows to check for early |
| * return values instead of regular return values. |
| */ |
| Field flagField = targetClass.fieldByName("debuggerWatching"); |
| targetClass.setValue(flagField, vm().mirrorOf(true)); |
| |
| |
| /* |
| * 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. |
| * |
| * The MethodExitEvent handler will keep score. |
| */ |
| |
| setBreakpoint("EarlyReturnTarg", "s_bytef", "(I)B"); |
| setBreakpoint("EarlyReturnTarg", "s_charf", "()C"); |
| setBreakpoint("EarlyReturnTarg", "s_doublef", "()D"); |
| setBreakpoint("EarlyReturnTarg", "s_floatf", "()F"); |
| setBreakpoint("EarlyReturnTarg", "s_intf", "()I"); |
| setBreakpoint("EarlyReturnTarg", "s_longf", "()J"); |
| setBreakpoint("EarlyReturnTarg", "s_shortf", "()S"); |
| setBreakpoint("EarlyReturnTarg", "s_booleanf", "()Z"); |
| |
| setBreakpoint("EarlyReturnTarg", "s_stringf", "()Ljava/lang/String;"); |
| setBreakpoint("EarlyReturnTarg", "s_classf", "()Ljava/lang/Class;"); |
| setBreakpoint("EarlyReturnTarg", "s_classLoaderf", "()Ljava/lang/ClassLoader;"); |
| setBreakpoint("EarlyReturnTarg", "s_threadf", "()Ljava/lang/Thread;"); |
| setBreakpoint("EarlyReturnTarg", "s_threadGroupf", "()Ljava/lang/ThreadGroup;"); |
| setBreakpoint("EarlyReturnTarg", "s_intArrayf", "()[I"); |
| setBreakpoint("EarlyReturnTarg", "s_nullObjectf", "()Ljava/lang/Object;"); |
| setBreakpoint("EarlyReturnTarg", "s_objectf", "()Ljava/lang/Object;"); |
| setBreakpoint("EarlyReturnTarg", "s_voidf", "()V"); |
| |
| setBreakpoint("EarlyReturnTarg", "i_bytef", "(I)B"); |
| setBreakpoint("EarlyReturnTarg", "i_charf", "()C"); |
| setBreakpoint("EarlyReturnTarg", "i_doublef", "()D"); |
| setBreakpoint("EarlyReturnTarg", "i_floatf", "()F"); |
| setBreakpoint("EarlyReturnTarg", "i_intf", "()I"); |
| setBreakpoint("EarlyReturnTarg", "i_longf", "()J"); |
| setBreakpoint("EarlyReturnTarg", "i_shortf", "()S"); |
| setBreakpoint("EarlyReturnTarg", "i_booleanf", "()Z"); |
| setBreakpoint("EarlyReturnTarg", "i_stringf", "()Ljava/lang/String;"); |
| setBreakpoint("EarlyReturnTarg", "i_intArrayf", "()[I"); |
| setBreakpoint("EarlyReturnTarg", "i_classf", "()Ljava/lang/Class;"); |
| setBreakpoint("EarlyReturnTarg", "i_classLoaderf", "()Ljava/lang/ClassLoader;"); |
| setBreakpoint("EarlyReturnTarg", "i_threadf", "()Ljava/lang/Thread;"); |
| setBreakpoint("EarlyReturnTarg", "i_threadGroupf", "()Ljava/lang/ThreadGroup;"); |
| setBreakpoint("EarlyReturnTarg", "i_nullObjectf", "()Ljava/lang/Object;"); |
| setBreakpoint("EarlyReturnTarg", "i_objectf", "()Ljava/lang/Object;"); |
| setBreakpoint("EarlyReturnTarg", "i_voidf", "()V"); |
| |
| /* Here we go. This adds 'this' as a listener so |
| * that our handlers above will be called. |
| */ |
| listenUntilVMDisconnect(); |
| |
| if (earlyReturns != expectedEarlyReturns) { |
| failure("failure: Expected " + expectedEarlyReturns + |
| ", but got " + earlyReturns); |
| } |
| System.out.println("All done, " + earlyReturns + " passed"); |
| |
| |
| if (!testFailed) { |
| System.out.println(); |
| System.out.println("EarlyReturnTest: passed"); |
| } else { |
| System.out.println(); |
| System.out.println("EarlyReturnTest: failed"); |
| throw new Exception("EarlyReturnTest: failed"); |
| } |
| } |
| } |