1 /*
2  * Copyright (c) 2003, 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 4870984
27  *  @summary  JPDA: Add support for RFE 4856541 - varargs
28  *
29  *  @author jjh
30  *
31  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
32  *  @run compile -g VarargsTest.java
33  *  @run main VarargsTest
34  */
35 import com.sun.jdi.*;
36 import com.sun.jdi.event.*;
37 import com.sun.jdi.request.*;
38 
39 import java.util.*;
40 
41     /********** target program **********/
42 
43 class VarargsTarg {
44 
45     // These are args that will get passed
46     static String[] strArray = new String[] {"a", "b"};
47     static int[] intArray = new int[] {1, 2};
48 
49     // We will pass these to a varargs instance method
50     static VarargsTarg vt1 = new VarargsTarg("vt1", "");
51     static VarargsTarg vt2 = new VarargsTarg("vt2", "");
52 
53     String iname;
54 
VarargsTarg(String .... name)55     VarargsTarg(String ... name) {
56         iname = "";
57         for (int ii = 0; ii < name.length; ii++) {
58             iname += name[ii];
59         }
60     }
61 
main(String[] args)62     public static void main(String[] args){
63         System.out.println("Howdy!");
64         /*
65          * This isn't really part of the test, it just shows
66          * the kinds of calls the debugger test will do and lets
67          * you verify how javac handles these calls.
68          */
69         System.out.println("debuggee: " + varString());
70         System.out.println("debuggee: " + varString(null));
71         System.out.println("debuggee: " + varString("a"));
72         System.out.println("debuggee: " + varString("b", "c"));
73         System.out.println("debuggee: " + fixedString(null));
74         System.out.println("debuggee: " + vt1.varStringInstance(vt1, vt2));
75         System.out.println("debuggge: " + varInt(1, 2, 3));
76         System.out.println("debuggee: " + varInteger( new Integer(89)));
77 
78         // Should be autoboxed: javac converts the ints to Integers
79         // Needs a new method in java.lang.Integer which is only
80         // in the generics workspace.
81         System.out.println("debugggee: " + varInteger(3, 5, 6));
82 
83         System.out.println("Goodbye from VarargsTarg!");
84         bkpt();
85     }
bkpt()86     static void bkpt() {
87     }
88 
89     /*
90      * Define the methods to be called from the debugger
91      */
fixedInt(int p1)92     static String fixedInt(int p1) {
93         return "" + p1;
94     }
95 
fixedInteger(Integer p1)96     static String fixedInteger(Integer p1) {
97         return "" + p1;
98     }
99 
varInt(int... ss)100      static String varInt(int... ss) {
101          String retVal = "";
102          for (int ii = 0; ii < ss.length; ii++) {
103              retVal += ss[ii];
104          }
105          return retVal;
106      }
107 
varInteger(Integer... ss)108     static String varInteger(Integer... ss) {
109         String retVal = "";
110         for (int ii = 0; ii < ss.length; ii++) {
111             retVal += ss[ii];
112         }
113         return retVal;
114     }
115 
varString(String... ss)116     static String varString(String... ss) {
117         if (ss == null) {
118             return "-null-";
119         }
120 
121         String retVal = "";
122         for (int ii = 0; ii < ss.length; ii++) {
123             retVal += ss[ii];
124         }
125         return retVal;
126     }
127 
varString2(int p1, String... ss)128     static String varString2(int p1, String... ss) {
129         return p1 + varString(ss);
130     }
131 
fixedString(String ss)132     static String fixedString(String ss) {
133         return "-fixed-";
134     }
135 
varStringInstance(VarargsTarg... args)136     String varStringInstance(VarargsTarg... args) {
137         if (args == null) {
138             return "-null-";
139         }
140         //System.out.println("debugee: ss length = " + ss.length);
141         String retVal = iname + ": ";
142         for (int ii = 0; ii < args.length; ii++) {
143             retVal += args[ii].iname;
144         }
145         return retVal;
146     }
147 
148 }
149 
150     /********** test program **********/
151 
152 public class VarargsTest extends TestScaffold {
153     ClassType targetClass;
154     ThreadReference mainThread;
155 
VarargsTest(String args[])156     VarargsTest (String args[]) {
157         super(args);
158     }
159 
main(String[] args)160     public static void main(String[] args)      throws Exception {
161         new VarargsTest(args).startTests();
162     }
163 
fail(String reason)164     void fail(String reason) {
165         failure(reason);
166     }
167 
168     /*
169      * Call a method in the debuggee and verify the return value.
170      */
doInvoke(Object ct, Method mm, List args, Object expected)171     void doInvoke(Object ct, Method mm, List args, Object expected) {
172         StringReference returnValue = null;
173         try {
174             returnValue = doInvokeNoVerify(ct, mm, args);
175         } catch (Exception ee) {
176             fail("failure: invokeMethod got exception : " + ee);
177             ee.printStackTrace();
178             return;
179         }
180         if (!returnValue.value().equals(expected)) {
181             fail("failure: expected \"" + expected + "\", got \"" +
182                  returnValue.value() + "\"");
183         }
184     }
185 
186     /*
187      * Call a method in the debuggee.
188      */
doInvokeNoVerify(Object ct, Method mm, List args)189     StringReference doInvokeNoVerify(Object ct, Method mm, List args)
190         throws Exception {
191         StringReference returnValue = null;
192         if (ct instanceof ClassType) {
193             returnValue = (StringReference)((ClassType)ct).
194                 invokeMethod(mainThread, mm, args, 0);
195         } else {
196             returnValue = (StringReference)((ObjectReference)ct).
197                 invokeMethod(mainThread, mm, args, 0);
198         }
199         return returnValue;
200     }
201 
202     /********** test core **********/
203 
runTests()204     protected void runTests() throws Exception {
205         /*
206          * Get to the top of main()
207          * to determine targetClass and mainThread
208          */
209         BreakpointEvent bpe = startToMain("VarargsTarg");
210         targetClass = (ClassType)bpe.location().declaringType();
211         mainThread = bpe.thread();
212 
213         /*
214          * Run past the calls the debuggee makes
215          * just to see what they do.
216          */
217         bpe = resumeTo("VarargsTarg", "bkpt", "()V");
218 
219         /*
220          * Find Method objects for varString and varString2
221          * Both are tested just to show that the code works
222          * if there is just one param or if there is more than one.
223          */
224         ReferenceType rt = findReferenceType("VarargsTarg");
225 
226         List mList;
227 
228         /*
229          * The test consists of calling the varargs static and instance methods
230          * (and constructor) passing primitives, Strings, and Objects, and also
231          * passing arrays of the above instead of individual args.
232          * The same code is used in the underlying JDI implementations
233          * for calling instance methods, static methods, and constructors
234          * so this test doesn't have to try all possible argument configurations
235          * with each type of method.
236          */
237 
238         mList = rt.methodsByName("varString");
239         Method varString = (Method)mList.get(0);
240 
241         mList = rt.methodsByName("varString2");
242         Method varString2 = (Method)mList.get(0);
243 
244         if (!varString.isVarArgs()) {
245             fail("failure: varString is not flagged as being var args");
246         }
247         if (!varString2.isVarArgs()) {
248             fail("failure: varString2 is not flagged as being var args");
249         }
250 
251         /*
252          * Setup arg lists for both varString and varString2 that
253          * have null in the varargs position.
254          */
255 
256         {
257             // call varString()
258             ArrayList nullArg1 = new ArrayList(0);
259             doInvoke(targetClass, varString, nullArg1,  "");
260         }
261         {
262             // call varString(null)
263             ArrayList nullArg1 = new ArrayList(1);
264             nullArg1.add(null);
265             doInvoke(targetClass, varString, nullArg1,  "-null-");
266         }
267         {
268             // call varString(9)
269             ArrayList nullArg2 = new ArrayList(1);
270             nullArg2.add(vm().mirrorOf(9));
271             doInvoke(targetClass, varString2, nullArg2,  "9");
272         }
273         {
274             // call varString(9, null)
275             ArrayList nullArg2 = new ArrayList(2);
276             nullArg2.add(vm().mirrorOf(9));
277             nullArg2.add(null);
278             doInvoke(targetClass, varString2, nullArg2,  "9-null-");
279         }
280         {
281             ArrayList args1 = new ArrayList(4);
282             args1.add(vm().mirrorOf("1"));
283 
284             // call varString("1")
285             doInvoke(targetClass, varString, args1, "1");
286 
287             // call varString("1", "2")
288             args1.add(vm().mirrorOf("2"));
289             args1.add(vm().mirrorOf("3"));
290             args1.add(vm().mirrorOf("4"));
291             doInvoke(targetClass, varString, args1, "1234");
292         }
293         {
294             ArrayList args2 = new ArrayList(2);
295             args2.add(vm().mirrorOf(9));
296             args2.add(vm().mirrorOf("1"));
297 
298             // call varString2(9, "1");
299             doInvoke(targetClass, varString2, args2, "91");
300 
301             // call varString2(9, "1", "2");
302             args2.add(vm().mirrorOf("2"));
303             doInvoke(targetClass, varString2, args2, "912");
304         }
305 
306         {
307             /*
308              * Passing an array of Strings should work too.
309              */
310             Field ff = targetClass.fieldByName("strArray");
311             Value vv1 = targetClass.getValue(ff);
312 
313             // call varString(new String[] {"a", "b"})
314             ArrayList argsArray = new ArrayList(1);
315             argsArray.add(vv1);
316             doInvoke(targetClass, varString, argsArray, "ab");
317 
318             /*
319              * But passing an array of Strings and another String
320              * should fail
321              */
322             argsArray.add(vm().mirrorOf("x"));
323             boolean isOk = false;
324             try {
325                 // call varString(new String[] {"a", "b"}, "x")
326                 doInvokeNoVerify(targetClass, varString, argsArray);
327             } catch (Exception ee) {
328                 /*
329                  * Since the number of args passed is > than
330                  * the number of params, JDI assumes they are var args
331                  * and tries to put the array containing the "a" and
332                  * "be" elements into a the first element of an array
333                  * of Strings.  This fails because you can't store
334                  * an array into a String
335                  */
336                 isOk = true;
337                 //ee.printStackTrace();
338             }
339             if (!isOk) {
340                 fail("failure: an array and a String didn't cause an exception");
341             }
342         }
343 
344         {
345             /*
346              * Test calling instance method instead of static method,
347              * and passing non-String objects
348              */
349             Field vtField = targetClass.fieldByName("vt1");
350             Value vv1 = targetClass.getValue(vtField);
351 
352             vtField = targetClass.fieldByName("vt2");
353             Value vv2 = targetClass.getValue(vtField);
354 
355             /* Create a new instance by calling the varargs
356              * ctor.
357              * call new VarargsTarg("vt3", "xx");
358              */
359             Value vv3;
360             {
361                 mList = rt.methodsByName("<init>");
362                 Method ctor = (Method)mList.get(0);
363                 if (!ctor.isVarArgs()) {
364                     fail("failure: Constructor is not varargs");
365                 }
366                 ArrayList argsArray = new ArrayList(2);
367                 argsArray.add(vm().mirrorOf("vt3"));
368                 argsArray.add(vm().mirrorOf("xx"));
369                 vv3 = targetClass.newInstance(mainThread, ctor, argsArray, 0);
370             }
371             // call vt1.varStringInstance(vv1, vv2, vv3)
372             mList = rt.methodsByName("varStringInstance");
373             Method varStringInstance = (Method)mList.get(0);
374 
375             ArrayList argsArray = new ArrayList(3);
376             argsArray.add(vv1);
377             argsArray.add(vv2);
378             argsArray.add(vv3);
379             doInvoke(vv1, varStringInstance, argsArray, "vt1: vt1vt2vt3xx");
380         }
381         {
382             /*
383              * tests with primitive types
384              */
385             List mlist;
386             Method mm;
387             ArrayList ll = new ArrayList(2);
388 
389             // call fixedInt(21)
390             mlist = rt.methodsByName("fixedInt");
391             mm = (Method)mlist.get(0);
392             ll.add(vm().mirrorOf(21));
393             doInvoke(targetClass, mm, ll, "21");
394 
395             // autoboxing is not implemented in JDI.
396             // call fixedInteger(21)
397             //mlist = rt.methodsByName("fixedInteger");
398             //mm = (Method)mlist.get(0);
399             //doInvoke(targetClass, mm, ll, "21");
400 
401             mlist = rt.methodsByName("varInt");
402             mm = (Method)mlist.get(0);
403 
404             // call varInt( new int[] {1, 2});
405             Field ff = targetClass.fieldByName("intArray");
406             Value vv1 = targetClass.getValue(ff);
407             ll.set(0, vv1);
408             doInvoke(targetClass, mm, ll, "12");
409 
410             // call varInt(21, 22)
411             ll.set(0, vm().mirrorOf(21));
412             ll.add(vm().mirrorOf(22));
413             doInvoke(targetClass, mm, ll, "2122");
414 
415             mlist = rt.methodsByName("varInteger");
416             mm = (Method)mlist.get(0);
417 
418             // call varInteger(1, 2)
419             // autoboxing is not implemented.
420             //doInvoke(targetClass, mm, ll, "2122");
421         }
422 
423         /*
424          * We don't really need this for the test, but
425          * but without it, we sometimes hit 4728096.
426          */
427         listenUntilVMDisconnect();
428         /*
429          * deal with results of test
430          * if anything has called failure("foo") testFailed will be true
431          */
432         if (!testFailed) {
433             println("VarargsTest: passed");
434         } else {
435             throw new Exception("VarargsTest: failed");
436         }
437     }
438 }
439