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