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 4409241 4432820
27 * @summary Test the bug fix for: MethodExitEvents disappear when Object-Methods are called from main
28 * @author Tim Bell
29 *
30 * @run build TestScaffold VMConnection TargetListener TargetAdapter
31 * @run compile -g MethodEntryExitEvents.java
32 * @run driver MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee
33 * @run driver MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee
34 * @run driver MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee
35 */
36import com.sun.jdi.*;
37import com.sun.jdi.event.*;
38import com.sun.jdi.request.*;
39import java.util.*;
40
41class t2 {
42    public static void sayHello1(int i, int j) {
43        sayHello2(i, j);
44    }
45    public static void sayHello2(int i, int j) {
46        sayHello3(i, j);
47    }
48    public static void sayHello3(int i, int j) {
49        sayHello4(i, j);
50    }
51    public static void sayHello4(int i, int j) {
52        sayHello5(i, j);
53    }
54    public static void sayHello5(int i, int j) {
55        if (i < 2) {
56            sayHello1(++i, j);
57        } else {
58            System.out.print  ("MethodEntryExitEventsDebugee: ");
59            System.out.print  ("    -->> Hello.  j is: ");
60            System.out.print  (j);
61            System.out.println(" <<--");
62        }
63    }
64}
65
66class MethodEntryExitEventsDebugee {
67    public static void loopComplete () {
68        /*
69         * The implementation here is deliberately inefficient
70         * because the debugger is still watching this method.
71         */
72        StringBuffer sb = new StringBuffer();
73        sb.append ("MethodEntryExitEventsDebugee: ");
74        sb.append ("Executing loopComplete method for a graceful shutdown...");
75        String s = sb.toString();
76        for (int i = 0; i < s.length(); i++) {
77            char c = s.charAt(i);
78            System.out.print(c);
79        }
80        System.out.println();
81    }
82    public static void main(String[] args) {
83        t2 test = new t2();
84        for (int j = 0; j < 3; j++) {
85            test.sayHello1(0, j);
86        }
87        loopComplete();
88    }
89}
90
91
92public class MethodEntryExitEvents extends TestScaffold {
93    int sessionSuspendPolicy = EventRequest.SUSPEND_ALL;
94    StepRequest stepReq = null; //Only one step request allowed per thread
95    boolean finishedCounting = false;
96
97    /*
98     * Enter main() , then t2.<init>, then sayHello[1,2,3,4,5] 15 times 3 loops,
99     * then loopComplete()
100     */
101    final int expectedEntryCount = 1 + 1 + (15 * 3) + 1;
102    int methodEntryCount = 0;
103
104    /*
105     * Exit t2.<init>, then sayHello[1,2,3,4,5] 15 times 3 loopa
106     * (event monitoring is cancelled before we exit loopComplete() or main())
107     */
108    final int expectedExitCount = 1 + (15 * 3);
109    int methodExitCount = 0;
110
111    // Classes which we are interested in
112    private List includes = Arrays.asList(new String[] {
113        "MethodEntryExitEventsDebugee",
114        "t2"
115    });
116
117    MethodEntryExitEvents (String args[]) {
118        super(args);
119    }
120
121    private void usage(String[] args) throws Exception {
122        StringBuffer sb = new StringBuffer("Usage: ");
123        sb.append(System.getProperty("line.separator"));
124        sb.append("  java ");
125        sb.append(getClass().getName());
126        sb.append(" [SUSPEND_NONE | SUSPEND_EVENT_THREAD | SUSPEND_ALL]");
127        sb.append(" [MethodEntryExitEventsDebugee | -connect <connector options...>] ");
128        throw new Exception (sb.toString());
129    }
130
131    public static void main(String[] args)      throws Exception {
132        MethodEntryExitEvents meee = new MethodEntryExitEvents (args);
133        meee.startTests();
134    }
135
136    public void exceptionThrown(ExceptionEvent event) {
137        System.out.println("Exception: " + event.exception());
138        System.out.println(" at catch location: " + event.catchLocation());
139
140        // Step to the catch
141        if (stepReq == null) {
142            stepReq =
143                eventRequestManager().createStepRequest(event.thread(),
144                                                        StepRequest.STEP_MIN,
145                                                        StepRequest.STEP_INTO);
146            stepReq.addCountFilter(1);  // next step only
147            stepReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
148        }
149        stepReq.enable();
150    }
151    public void stepCompleted(StepEvent event) {
152        System.out.println("stepCompleted: line#=" +
153                           event.location().lineNumber() +
154                           " event=" + event);
155        // disable the step and then run to completion
156        //eventRequestManager().deleteEventRequest(event.request());
157        StepRequest str= (StepRequest)event.request();
158        str.disable();
159    }
160    public void methodEntered(MethodEntryEvent event) {
161        if (!includes.contains(event.method().declaringType().name())) {
162            return;
163        }
164
165        if (! finishedCounting) {
166            // We have to count the entry to loopComplete, but
167            // not the exit
168            methodEntryCount++;
169            System.out.print  (" Method entry number: ");
170            System.out.print  (methodEntryCount);
171            System.out.print  ("  :  ");
172            System.out.println(event);
173            if ("loopComplete".equals(event.method().name())) {
174                finishedCounting = true;
175            }
176        }
177    }
178
179    public void methodExited(MethodExitEvent event) {
180        if (!includes.contains(event.method().declaringType().name())) {
181            return;
182        }
183
184        if (! finishedCounting){
185            methodExitCount++;
186            System.out.print  (" Method exit  number: ");
187            System.out.print  (methodExitCount);
188            System.out.print  ("  :  ");
189            System.out.println(event);
190        }
191    }
192
193    protected void runTests() throws Exception {
194        if (args.length < 1) {
195            usage(args);
196        }
197        //Pick up the SUSPEND_xxx in first argument
198        if ("SUSPEND_NONE".equals(args[0])) {
199            sessionSuspendPolicy = EventRequest.SUSPEND_NONE;
200        } else if ("SUSPEND_EVENT_THREAD".equals(args[0])) {
201            sessionSuspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
202        } else if ("SUSPEND_ALL".equals(args[0])) {
203            sessionSuspendPolicy = EventRequest.SUSPEND_ALL;
204        } else {
205            usage(args);
206        }
207        System.out.print("Suspend policy is: ");
208        System.out.println(args[0]);
209
210        // Skip the test arg
211        String[] args2 = new String[args.length - 1];
212        System.arraycopy(args, 1, args2, 0, args.length - 1);
213
214        if (args2.length < 1) {
215            usage(args2);
216        }
217        List argList = new ArrayList(Arrays.asList(args2));
218        System.out.println("run args: " + argList);
219        connect((String[]) argList.toArray(args2));
220        waitForVMStart();
221
222        // Determine main thread
223        ClassPrepareEvent e = resumeToPrepareOf("MethodEntryExitEventsDebugee");
224        mainThread = e.thread();
225
226        try {
227
228            /*
229             * Ask for Exception events
230             */
231            ExceptionRequest exceptionRequest =
232                eventRequestManager().createExceptionRequest(null, // refType (null == all instances)
233                                                             true, // notifyCaught
234                                                             true);// notifyUncaught
235            exceptionRequest.addThreadFilter(mainThread);
236            exceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
237            exceptionRequest.enable();
238
239            /*
240             * Ask for method entry events
241             */
242            MethodEntryRequest entryRequest =
243               eventRequestManager().createMethodEntryRequest();
244            entryRequest.addThreadFilter(mainThread);
245            entryRequest.setSuspendPolicy(sessionSuspendPolicy);
246            entryRequest.enable();
247
248            /*
249             * Ask for method exit events
250             */
251            MethodExitRequest exitRequest =
252                eventRequestManager().createMethodExitRequest();
253            exitRequest.addThreadFilter(mainThread);
254            exitRequest.setSuspendPolicy(sessionSuspendPolicy);
255            exitRequest.enable();
256
257            /*
258             * We are now set up to receive the notifications we want.
259             * Here we go.  This adds 'this' as a listener so
260             * that our handlers above will be called.
261             */
262
263            listenUntilVMDisconnect();
264            System.out.println("All done...");
265
266        } catch (Exception ex){
267            ex.printStackTrace();
268            testFailed = true;
269        }
270
271        if ((methodEntryCount != expectedEntryCount) ||
272            (methodExitCount != expectedExitCount)) {
273            testFailed = true;
274        }
275        if (!testFailed) {
276            System.out.println();
277            System.out.println("MethodEntryExitEvents: passed");
278            System.out.print  ("    Method entry count: ");
279            System.out.println(methodEntryCount);
280            System.out.print  ("    Method exit  count: ");
281            System.out.println(methodExitCount);
282        } else {
283            System.out.println();
284            System.out.println("MethodEntryExitEvents: failed");
285            System.out.print  ("    expected method entry count: ");
286            System.out.println(expectedEntryCount);
287            System.out.print  ("    observed method entry count: ");
288            System.out.println(methodEntryCount);
289            System.out.print  ("    expected method exit  count: ");
290            System.out.println(expectedExitCount);
291            System.out.print  ("    observed method exit  count: ");
292            System.out.println(methodExitCount);
293            throw new Exception("MethodEntryExitEvents: failed");
294        }
295    }
296}
297