1 /*
   2  * Copyright (c) 2001, 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 4467564
  27  *  @summary Test the popping of frames in synchronous context
  28  *           (that is, when stopped at an event)
  29  *
  30  *  @author Robert Field
  31  *
  32  *  @modules jdk.jdi
  33  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  34  *  @run compile -g PopSynchronousTest.java
  35  *  @run driver PopSynchronousTest
  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 PopSynchronousTarg {
  46     static String s;
  47     static PopSynchronousTarg sole;
  48 
  49     synchronized void a(int y, boolean w) {
  50         if (y == 6 && w) {
  51             s += "@";
  52         } else {
  53             s += " aArgFail ";
  54         }
  55     }
  56     String b(String h) {
  57         if (h.equals("yo")) {
  58             s += "[";
  59         } else {
  60             s += " bArgFail ";
  61         }
  62         a(6, true);
  63         s += "]";
  64         return s;
  65     }
  66     long c() {
  67         s += "<";
  68         synchronized (s) {
  69             b("yo");
  70         }
  71         s += ">";
  72         return 17;
  73     }
  74     static void p() {
  75         s += "(";
  76         if (sole.c() != 17) {
  77             s += " cReturnFail ";
  78         }
  79         s += ")";
  80     }
  81     static void report() {
  82     }
  83     public static void main(String[] args){
  84         s = new String();
  85         sole = new PopSynchronousTarg();
  86         for (int i = 0; i < 100; ++i) {
  87             p();
  88             // System.out.println(s);
  89             report();
  90         }
  91     }
  92 }
  93 
  94     /********** test program **********/
  95 
  96 public class PopSynchronousTest extends TestScaffold {
  97     ReferenceType targetClass;
  98     ThreadReference mainThread;
  99     int stateIndex = 0;
 100     String expected = "";
 101     static final String[] calls =  {"a", "b", "c", "p", "main"};
 102     static final int popMax = calls.length - 1;
 103     static final String[] states =
 104     {"main-i", "p-e", "p-i", "c-e", "c-i", "b-e", "b-i", "a-e", "a-l", "b-l", "c-l", "p-l", "main-r", "report-e"};
 105     static final String[] output =
 106     {"",       "",    "(",   "",    "<",   "",    "[",   "",    "@",   "]",   ">",   ")",   "",       ""};
 107 
 108 
 109     PopSynchronousTest (String args[]) {
 110         super(args);
 111     }
 112 
 113     public static void main(String[] args)      throws Exception {
 114         new PopSynchronousTest(args).startTests();
 115     }
 116 
 117 
 118     /********** test assist **********/
 119 
 120     StackFrame frameFor(String methodName) throws Exception {
 121         Iterator it = mainThread.frames().iterator();
 122 
 123         while (it.hasNext()) {
 124             StackFrame frame = (StackFrame)it.next();
 125             if (frame.location().method().name().equals(methodName)) {
 126                 return frame;
 127             }
 128         }
 129         failure("FAIL: " + methodName + " not on stack");
 130         return null;
 131     }
 132 
 133     String actual() throws Exception {
 134         Field field = targetClass.fieldByName("s");
 135         StringReference sr = (StringReference)(targetClass.getValue(field));
 136         return sr.value();
 137     }
 138 
 139     void checkExpected() throws Exception {
 140         if (!actual().equals(expected)) {
 141             failure("FAIL: expected value: " + expected +
 142                     " got: " + actual());
 143         }
 144     }
 145 
 146     int methodIndex(String methodName) {
 147         for (int i = 0; i < popMax; ++i) {
 148             if (methodName.equals(calls[i])) {
 149                 return i;
 150             }
 151         }
 152         return -1;
 153     }
 154 
 155     boolean isTop(String methodName) throws Exception {
 156         return mainThread.frame(0).location().method().name().equals(methodName);
 157     }
 158 
 159     void checkTop(String methodName, boolean atStart) throws Exception {
 160         Location loc = mainThread.frame(0).location();
 161         Method meth = loc.method();
 162         String name = meth.name();
 163         if (!isTop(methodName)) {
 164             failure("FAIL: expected " + methodName +
 165                     " at top of stack, instead: " + name);
 166         } else if ((meth.location().codeIndex() == loc.codeIndex()) != atStart) {
 167             failure("FAIL: not at expect position: " + loc.codeIndex());
 168         }
 169     }
 170 
 171     void checkState() throws Exception {
 172         String name = states[stateIndex];
 173         int dash = name.indexOf('-');
 174         String methodName = name.substring(0,dash);
 175         String posName = name.substring(dash+1);
 176         checkTop(methodName, posName.equals("e"));
 177         checkExpected();
 178     }
 179 
 180     void incrementState() {
 181         stateIndex = (stateIndex + 1) % (states.length);
 182     }
 183 
 184     void resetState(String stateName) {
 185         for (int i=0; i < states.length; ++i) {
 186             if (states[i].equals(stateName)) {
 187                 stateIndex = i;
 188                 return;
 189             }
 190         }
 191         failure("TEST FAILURE: cannot find state: " + stateName);
 192     }
 193 
 194     void resetExpected() throws Exception {
 195         println("Current value: " + actual());
 196         Field field = targetClass.fieldByName("s");
 197         expected = "";
 198         ((ClassType)targetClass).setValue(field, vm().mirrorOf(expected));
 199     }
 200 
 201     void stateTo(String stateName) {
 202         do {
 203             incrementState();
 204             expected += output[stateIndex];
 205         } while(!states[stateIndex].equals(stateName));
 206     }
 207 
 208     void resumeTo(String methodName) throws Exception {
 209         List meths = targetClass.methodsByName(methodName);
 210         Method meth = (Method)(meths.get(0));
 211         resumeTo(meth.location());
 212         stateTo(methodName + "-e");
 213         checkState();
 214     }
 215 
 216     void pop(String methodName) throws Exception {
 217         mainThread.popFrames(frameFor(methodName));
 218         resetState(methodName + "-e");
 219         --stateIndex;
 220         checkState();
 221     }
 222 
 223     void reenter(String methodName) throws Exception {
 224         pop(methodName);
 225         stepIntoInstruction(mainThread);
 226         incrementState();
 227         checkState();
 228     }
 229 
 230     /********** test core **********/
 231 
 232     protected void runTests() throws Exception {
 233         /*
 234          * Get to the top of main()
 235          * to determine targetClass and mainThread
 236          */
 237         BreakpointEvent bpe = startToMain("PopSynchronousTarg");
 238         targetClass = bpe.location().declaringType();
 239         mainThread = bpe.thread();
 240 
 241         /*
 242          * Testing
 243          */
 244 
 245         /* individual tests */
 246         for (int i = 0; i < popMax; ++i) {
 247             String from = calls[i];
 248             for (int j = i; j < popMax; ++j) {
 249                 String to = calls[j];
 250                 String prev = calls[j+1];
 251                 println("TEST pop from '" + from + "' to '" + to + "'");
 252                 resumeTo(from);
 253                 reenter(to);
 254                 resumeTo("report");
 255                 resetExpected();
 256             }
 257         }
 258 
 259         /* sequential tests */
 260 
 261         println("TEST pop a b c p");
 262         resumeTo("a");
 263         pop("a");
 264         pop("b");
 265         pop("c");
 266         pop("p");
 267         resumeTo("report");
 268         resetExpected();
 269 
 270         println("TEST pop a c p");
 271         resumeTo("a");
 272         pop("a");
 273         pop("c");
 274         pop("p");
 275         resumeTo("report");
 276         resetExpected();
 277 
 278         println("TEST stress a");
 279         resumeTo("a");
 280         for (int i = 0; i < 100; ++i) {
 281             reenter("a");
 282         }
 283         resumeTo("report");
 284         resetExpected();
 285 
 286         println("TEST stress c");
 287         resumeTo("c");
 288         for (int i = 0; i < 100; ++i) {
 289             reenter("c");
 290         }
 291         resumeTo("report");
 292         resetExpected();
 293 
 294         /*
 295          * we are done, get rid of target
 296          */
 297         vm().dispose();
 298 
 299         /*
 300          * deal with results of test
 301          * if anything has called failure("foo") testFailed will be true
 302          */
 303         if (!testFailed) {
 304             println("PopSynchronousTest: passed");
 305         } else {
 306             throw new Exception("PopSynchronousTest: failed");
 307         }
 308     }
 309 }