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