1 /*
   2  * Copyright (c) 2000, 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 4326648 4768329
  27  * @summary Test to verify that table entries are generated for all final
  28  *          locals when a class is built for debug, even if they could be
  29  *          inlined otherwise.
  30  * @author Tim Bell
  31  *
  32  * @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  * @run compile -g FinalLocalsTest.java
  34  * @run driver FinalLocalsTest
  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 FinalLocalsTarg {
  45     public void test1 (final int t, int k){
  46         String s1 = "first";
  47         final int z = 0;
  48         if (true) {
  49             final float r = 10.00f;
  50             boolean b = true;
  51             System.out.println(r);
  52         }
  53     }
  54     public void hi(){
  55         return;
  56     }
  57     public static void main(String[] args) {
  58         System.out.print("in FinalLocalsTarg:");
  59         new FinalLocalsTarg().hi();
  60         return;
  61     }
  62 }
  63 
  64     /********** test program **********/
  65 
  66 public class FinalLocalsTest extends TestScaffold {
  67     ReferenceType targetClass;
  68     ThreadReference mainThread;
  69 
  70     FinalLocalsTest (String args[]) {
  71         super(args);
  72     }
  73 
  74     public static void main(String[] args)      throws Exception {
  75         new FinalLocalsTest(args).startTests();
  76     }
  77 
  78     /********** test core **********/
  79     static final int VARIABLES = 1;
  80     static final int BYNAME = 2;
  81     static final int ARGUMENTS = 3;
  82     /*
  83      * Take a String containing comma separated values
  84      * and return those values in a TreeSet.
  85      */
  86     private TreeSet buildSet(String in) {
  87         TreeSet result = new TreeSet();
  88         StringTokenizer tt = new StringTokenizer(in, ",");
  89         while (tt.hasMoreTokens()) {
  90             String ss = tt.nextToken();
  91             if (! result.add(ss)) {
  92                 failure ("Duplicate entry \"" + ss + "\" in string: " +
  93                          in + " is not allowed");
  94             }
  95         }
  96         return result;
  97     }
  98 
  99     private void test(Method method, int which, String name, String expected) {
 100         String got = testCase(method, which);
 101         System.out.println(" test() comparing expected = " + expected +
 102                            " to got = " + got);
 103         TreeSet expectedSet = buildSet(expected);
 104         TreeSet gotSet = buildSet(got);
 105 
 106         while (! expectedSet.isEmpty()) {
 107             String ee = (String)expectedSet.first();
 108             expectedSet.remove(ee);
 109             if (gotSet.contains(ee)) {
 110                 gotSet.remove(ee);
 111             } else {
 112                 failure (name + " Expected entry \"" + ee + "\" not found");
 113             }
 114         }
 115 
 116         //assert expectedSet.isEmpty() : name + " expected set should have been emptied";
 117 
 118         if (! gotSet.isEmpty()) {
 119             StringBuffer sb = new StringBuffer();
 120             Iterator it = gotSet.iterator();
 121             while (it.hasNext()) {
 122                 sb.append(it.next());
 123                 if (it.hasNext()) {
 124                     sb.append(",");
 125                 }
 126             }
 127             failure (name + " Unexpected entries found: " + sb.toString());
 128         }
 129     }
 130 
 131     String testCase(Method method, int which) {
 132         try {
 133             List vars;
 134             switch (which) {
 135                 case VARIABLES:
 136                     vars = method.variables();
 137                     break;
 138                 case BYNAME:
 139                     vars = method.variablesByName("s1");
 140                     break;
 141                 case ARGUMENTS:
 142                     vars = method.arguments();
 143                     break;
 144                 default:
 145                     throw new InternalException("should not happen");
 146             }
 147             StringBuffer sb = new StringBuffer();
 148             for (Iterator it = vars.iterator(); it.hasNext(); ) {
 149                 LocalVariable lv = (LocalVariable)it.next();
 150                 if (sb.length() > 0) {
 151                     sb.append(",");
 152                 }
 153                 sb.append(lv.name());
 154             }
 155             return sb.toString();
 156         } catch (Exception exc) {
 157             String st = exc.getClass().getName();
 158             int inx = st.lastIndexOf('.');
 159             return st.substring(inx+1);
 160         }
 161     }
 162 
 163     protected void runTests() throws Exception {
 164         /*
 165          * Get to the top of main()
 166          * to determine targetClass and mainThread
 167          */
 168         BreakpointEvent bpe = startToMain("FinalLocalsTarg");
 169         targetClass = bpe.location().declaringType();
 170         mainThread = bpe.thread();
 171         EventRequestManager erm = vm().eventRequestManager();
 172 
 173         /*
 174          * Get to a point where the classes are loaded.
 175          */
 176         BreakpointEvent bp = resumeTo("FinalLocalsTarg", "hi", "()V");
 177 
 178         ReferenceType rt = findReferenceType("FinalLocalsTarg");
 179         if (rt == null) {
 180             throw new Exception("FinalLocalsTarg: not loaded");
 181         }
 182 
 183         /*
 184          * Inspect the LocalVariableTable attributes for method "test1"
 185          * NOTE: .class files compiled with some versions of javac will
 186          * give results listed in different order.  That's OK.
 187          */
 188         Method method = findMethod(rt, "test1", "(II)V");
 189         if (method == null) {
 190             throw new Exception("Method not found");
 191         }
 192         test(method, VARIABLES, "VARIABLES",
 193              "t,k,s1,z,r,b");
 194         test(method, BYNAME, "BYNAME",
 195              "s1");
 196         test(method, ARGUMENTS, "ARGUMENTS",
 197              "t,k");
 198 
 199         /*
 200          * All Done.  Resume the target listening for events
 201          */
 202         listenUntilVMDisconnect();
 203 
 204         /*
 205          * deal with results of test
 206          * if anything has called failure("foo") testFailed will be true
 207          */
 208         if (!testFailed) {
 209             println("FinalLocalsTest: passed");
 210         } else {
 211             throw new Exception("FinalLocalsTest: failed");
 212         }
 213     }
 214 }