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