| /* | |
| * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /** | |
| * @test | |
| * @bug 4467564 | |
| * @summary Test the popping of frames in synchronous context | |
| * (that is, when stopped at an event) | |
| * @author Robert Field | |
| * | |
| * @run build TestScaffold VMConnection TargetListener TargetAdapter | |
| * @run compile -g PopSynchronousTest.java | |
| * @run driver PopSynchronousTest | |
| */ | |
| import com.sun.jdi.*; | |
| import com.sun.jdi.event.*; | |
| import com.sun.jdi.request.*; | |
| import java.util.*; | |
| /********** target program **********/ | |
| class PopSynchronousTarg { | |
| static String s; | |
| static PopSynchronousTarg sole; | |
| synchronized void a(int y, boolean w) { | |
| if (y == 6 && w) { | |
| s += "@"; | |
| } else { | |
| s += " aArgFail "; | |
| } | |
| } | |
| String b(String h) { | |
| if (h.equals("yo")) { | |
| s += "["; | |
| } else { | |
| s += " bArgFail "; | |
| } | |
| a(6, true); | |
| s += "]"; | |
| return s; | |
| } | |
| long c() { | |
| s += "<"; | |
| synchronized (s) { | |
| b("yo"); | |
| } | |
| s += ">"; | |
| return 17; | |
| } | |
| static void p() { | |
| s += "("; | |
| if (sole.c() != 17) { | |
| s += " cReturnFail "; | |
| } | |
| s += ")"; | |
| } | |
| static void report() { | |
| } | |
| public static void main(String[] args){ | |
| s = new String(); | |
| sole = new PopSynchronousTarg(); | |
| for (int i = 0; i < 100; ++i) { | |
| p(); | |
| // System.out.println(s); | |
| report(); | |
| } | |
| } | |
| } | |
| /********** test program **********/ | |
| public class PopSynchronousTest extends TestScaffold { | |
| ReferenceType targetClass; | |
| ThreadReference mainThread; | |
| int stateIndex = 0; | |
| String expected = ""; | |
| static final String[] calls = {"a", "b", "c", "p", "main"}; | |
| static final int popMax = calls.length - 1; | |
| static final String[] states = | |
| {"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"}; | |
| static final String[] output = | |
| {"", "", "(", "", "<", "", "[", "", "@", "]", ">", ")", "", ""}; | |
| PopSynchronousTest (String args[]) { | |
| super(args); | |
| } | |
| public static void main(String[] args) throws Exception { | |
| new PopSynchronousTest(args).startTests(); | |
| } | |
| /********** test assist **********/ | |
| StackFrame frameFor(String methodName) throws Exception { | |
| Iterator it = mainThread.frames().iterator(); | |
| while (it.hasNext()) { | |
| StackFrame frame = (StackFrame)it.next(); | |
| if (frame.location().method().name().equals(methodName)) { | |
| return frame; | |
| } | |
| } | |
| failure("FAIL: " + methodName + " not on stack"); | |
| return null; | |
| } | |
| String actual() throws Exception { | |
| Field field = targetClass.fieldByName("s"); | |
| StringReference sr = (StringReference)(targetClass.getValue(field)); | |
| return sr.value(); | |
| } | |
| void checkExpected() throws Exception { | |
| if (!actual().equals(expected)) { | |
| failure("FAIL: expected value: " + expected + | |
| " got: " + actual()); | |
| } | |
| } | |
| int methodIndex(String methodName) { | |
| for (int i = 0; i < popMax; ++i) { | |
| if (methodName.equals(calls[i])) { | |
| return i; | |
| } | |
| } | |
| return -1; | |
| } | |
| boolean isTop(String methodName) throws Exception { | |
| return mainThread.frame(0).location().method().name().equals(methodName); | |
| } | |
| void checkTop(String methodName, boolean atStart) throws Exception { | |
| Location loc = mainThread.frame(0).location(); | |
| Method meth = loc.method(); | |
| String name = meth.name(); | |
| if (!isTop(methodName)) { | |
| failure("FAIL: expected " + methodName + | |
| " at top of stack, instead: " + name); | |
| } else if ((meth.location().codeIndex() == loc.codeIndex()) != atStart) { | |
| failure("FAIL: not at expect position: " + loc.codeIndex()); | |
| } | |
| } | |
| void checkState() throws Exception { | |
| String name = states[stateIndex]; | |
| int dash = name.indexOf('-'); | |
| String methodName = name.substring(0,dash); | |
| String posName = name.substring(dash+1); | |
| checkTop(methodName, posName.equals("e")); | |
| checkExpected(); | |
| } | |
| void incrementState() { | |
| stateIndex = (stateIndex + 1) % (states.length); | |
| } | |
| void resetState(String stateName) { | |
| for (int i=0; i < states.length; ++i) { | |
| if (states[i].equals(stateName)) { | |
| stateIndex = i; | |
| return; | |
| } | |
| } | |
| failure("TEST FAILURE: cannot find state: " + stateName); | |
| } | |
| void resetExpected() throws Exception { | |
| println("Current value: " + actual()); | |
| Field field = targetClass.fieldByName("s"); | |
| expected = ""; | |
| ((ClassType)targetClass).setValue(field, vm().mirrorOf(expected)); | |
| } | |
| void stateTo(String stateName) { | |
| do { | |
| incrementState(); | |
| expected += output[stateIndex]; | |
| } while(!states[stateIndex].equals(stateName)); | |
| } | |
| void resumeTo(String methodName) throws Exception { | |
| List meths = targetClass.methodsByName(methodName); | |
| Method meth = (Method)(meths.get(0)); | |
| resumeTo(meth.location()); | |
| stateTo(methodName + "-e"); | |
| checkState(); | |
| } | |
| void pop(String methodName) throws Exception { | |
| mainThread.popFrames(frameFor(methodName)); | |
| resetState(methodName + "-e"); | |
| --stateIndex; | |
| checkState(); | |
| } | |
| void reenter(String methodName) throws Exception { | |
| pop(methodName); | |
| stepIntoInstruction(mainThread); | |
| incrementState(); | |
| checkState(); | |
| } | |
| /********** test core **********/ | |
| protected void runTests() throws Exception { | |
| /* | |
| * Get to the top of main() | |
| * to determine targetClass and mainThread | |
| */ | |
| BreakpointEvent bpe = startToMain("PopSynchronousTarg"); | |
| targetClass = bpe.location().declaringType(); | |
| mainThread = bpe.thread(); | |
| /* | |
| * Testing | |
| */ | |
| /* individual tests */ | |
| for (int i = 0; i < popMax; ++i) { | |
| String from = calls[i]; | |
| for (int j = i; j < popMax; ++j) { | |
| String to = calls[j]; | |
| String prev = calls[j+1]; | |
| println("TEST pop from '" + from + "' to '" + to + "'"); | |
| resumeTo(from); | |
| reenter(to); | |
| resumeTo("report"); | |
| resetExpected(); | |
| } | |
| } | |
| /* sequential tests */ | |
| println("TEST pop a b c p"); | |
| resumeTo("a"); | |
| pop("a"); | |
| pop("b"); | |
| pop("c"); | |
| pop("p"); | |
| resumeTo("report"); | |
| resetExpected(); | |
| println("TEST pop a c p"); | |
| resumeTo("a"); | |
| pop("a"); | |
| pop("c"); | |
| pop("p"); | |
| resumeTo("report"); | |
| resetExpected(); | |
| println("TEST stress a"); | |
| resumeTo("a"); | |
| for (int i = 0; i < 100; ++i) { | |
| reenter("a"); | |
| } | |
| resumeTo("report"); | |
| resetExpected(); | |
| println("TEST stress c"); | |
| resumeTo("c"); | |
| for (int i = 0; i < 100; ++i) { | |
| reenter("c"); | |
| } | |
| resumeTo("report"); | |
| resetExpected(); | |
| /* | |
| * we are done, get rid of target | |
| */ | |
| vm().dispose(); | |
| /* | |
| * deal with results of test | |
| * if anything has called failure("foo") testFailed will be true | |
| */ | |
| if (!testFailed) { | |
| println("PopSynchronousTest: passed"); | |
| } else { | |
| throw new Exception("PopSynchronousTest: failed"); | |
| } | |
| } | |
| } |