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 
  54     VarargsTarg(String ... name) {
  55         iname = "";
  56         for (int ii = 0; ii < name.length; ii++) {
  57             iname += name[ii];
  58         }
  59     }
  60 
  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     }
  85     static void bkpt() {
  86     }
  87 
  88     /*
  89      * Define the methods to be called from the debugger
  90      */
  91     static String fixedInt(int p1) {
  92         return "" + p1;
  93     }
  94 
  95     static String fixedInteger(Integer p1) {
  96         return "" + p1;
  97     }
  98 
  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 
 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 
 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 
 127     static String varString2(int p1, String... ss) {
 128         return p1 + varString(ss);
 129     }
 130 
 131     static String fixedString(String ss) {
 132         return "-fixed-";
 133     }
 134 
 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 
 155     VarargsTest (String args[]) {
 156         super(args);
 157     }
 158 
 159     public static void main(String[] args)      throws Exception {
 160         new VarargsTest(args).startTests();
 161     }
 162 
 163     void fail(String reason) {
 164         failure(reason);
 165     }
 166 
 167     /*
 168      * Call a method in the debuggee and verify the return value.
 169      */
 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      */
 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 
 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 }