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