1 /*
2  * Copyright (c) 2002, 2018, 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 4629548
27  * @summary Deferred StepRequests are lost in multithreaded debuggee
28  * @comment converted from test/jdk/com/sun/jdi/DeferredStepTest.sh
29  *
30  * @library /test/lib
31  * @build DeferredStepTest
32  * @run main/othervm DeferredStepTest
33  */
34 
35 import jdk.test.lib.Asserts;
36 import jdk.test.lib.Utils;
37 import lib.jdb.JdbCommand;
38 import lib.jdb.JdbTest;
39 
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.regex.Matcher;
44 import java.util.regex.Pattern;
45 import java.util.stream.Collectors;
46 
47 class DeferredStepTestTarg {
48     static class  jj1 implements Runnable {
run()49         public void  run() {
50             int count = 0;
51 
52             for (int ii = 0; ii < 15; ii++) {
53                 int intInPotato04 = 666;
54                 ++count;                        // @1 breakpoint
55                 System.out.println("Thread: " + Thread.currentThread().getName());
56             }
57         }
58     }
59 
60     static class jj2 implements Runnable {
run()61         public void run() {
62             int count2 = 0;
63 
64             for (int ii = 0; ii < 15; ii++) {
65                 String StringInPotato05 = "I am";
66                 ++count2;                           // @2 breakpoint
67                 System.out.println("Thread: " + Thread.currentThread().getName());
68             }
69         }
70     }
71 
main(String argv[])72     public static void  main(String argv[]) {
73         System.out.println("Version = " + System.getProperty("java.version"));
74 
75         jj1 obj1 = new jj1();
76         jj2 obj2 = new jj2();
77         new Thread(obj1, "jj1").start();
78         new Thread(obj2, "jj2").start();
79     }
80 }
81 
82 public class DeferredStepTest extends JdbTest {
main(String argv[])83     public static void main(String argv[]) {
84         new DeferredStepTest().run();
85     }
86 
DeferredStepTest()87     private DeferredStepTest() {
88         super(DeferredStepTestTarg.class.getName());
89     }
90 
91     private static class ThreadData {
92         int lastLine = -1;  // line of the last stop
93         int minLine = -1;   // min line (-1 means "not known yet")
94         int maxLine = -1;   // max line (-1 means "not known yet")
95     }
96 
97     private Map<String, ThreadData> threadData = new HashMap<>();
98 
99     private Pattern threadRegexp = Pattern.compile("^(.+)\\[\\d+\\].*");
100     private Pattern lineRegexp = Pattern.compile("^(\\d+)\\b.*", Pattern.MULTILINE);
101 
102     // returns the 1st group of the pattern.
parse(Pattern p, String input)103     private String parse(Pattern p, String input) {
104         Matcher m = p.matcher(input);
105         if (!m.find()) {
106             throw new RuntimeException("Input '" + input + "' does not matches '" + p.pattern() + "'");
107         }
108         return m.group(1);
109     }
110 
next()111     private void next() {
112         List<String> reply = jdb.command(JdbCommand.next());
113         /*
114          * Each "next" produces something like ("Breakpoint hit" line only if the line has BP)
115          *   Step completed:
116          *     Breakpoint hit: "thread=jj2", DeferredStepTestTarg$jj2.run(), line=74 bci=12
117          *     74                    ++count2;                           // @ 2 breakpoint
118          *     <empty line>
119          *     jj2[1]
120          */
121         // detect thread from the last line
122         String lastLine = reply.get(reply.size() - 1);
123         String threadName = parse(threadRegexp, lastLine);
124         String wholeReply = reply.stream().collect(Collectors.joining(Utils.NEW_LINE));
125         int lineNum = Integer.parseInt(parse(lineRegexp, wholeReply));
126 
127         System.out.println("got: thread=" + threadName + ", line=" + lineNum);
128 
129         ThreadData data = threadData.get(threadName);
130         if (data == null) {
131             data = new ThreadData();
132             threadData.put(threadName, data);
133         }
134         processThreadData(threadName, lineNum, data);
135     }
136 
processThreadData(String threadName, int lineNum, ThreadData data)137     private void processThreadData(String threadName, int lineNum, ThreadData data) {
138         int lastLine = data.lastLine;
139         data.lastLine = lineNum;
140         if (lastLine < 0) {
141             // the 1st stop in the thread
142             return;
143         }
144         if (lineNum == lastLine + 1) {
145             // expected.
146             return;
147         }
148         if (lineNum < lastLine) {
149             // looks like step to the beginning of the cycle
150             if (data.minLine > 0) {
151                 // minLine and maxLine are not set - verify
152                 Asserts.assertEquals(lineNum, data.minLine, threadName + " - minLine");
153                 Asserts.assertEquals(lastLine, data.maxLine, threadName + " - maxLine");
154             } else {
155                 // set minLine/maxLine
156                 data.minLine = lineNum;
157                 data.maxLine = lastLine;
158             }
159             return;
160         }
161         throw new RuntimeException(threadName + " (line " + lineNum + ") - unexpected."
162                 + " lastLine=" + lastLine + ", minLine=" + data.minLine + ", maxLine=" + data.maxLine);
163     }
164 
165     @Override
runCases()166     protected void runCases() {
167         setBreakpoints(jdb, DeferredStepTestTarg.jj1.class.getName(),
168                 getTestSourcePath("DeferredStepTest.java"), 1);
169         setBreakpoints(jdb, DeferredStepTestTarg.jj2.class.getName(),
170                 getTestSourcePath("DeferredStepTest.java"), 2);
171 
172         // Run to breakpoint #1
173         jdb.command(JdbCommand.run());
174 
175         // 2 cycles (15 iterations) with 4 lines each, 1st break at 3rd line - 58 stops
176         for (int i = 0; i < 50; i++) {
177             next();
178         }
179     }
180 }
181