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