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