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