1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 */
18
19package org.apache.harmony.jpda.tests.jdwp.Deoptimization;
20
21import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
22import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
23import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
24import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
25import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
26import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
27
28public class DeoptimizationWithExceptionHandlingTest extends JDWPSyncTestCase {
29
30    @Override
31    protected String getDebuggeeClassName() {
32        return DeoptimizationWithExceptionHandlingDebuggee.class.getName();
33    }
34
35    /**
36     * This tests checks we properly handle exception event when we fully
37     * deoptimize the stack.
38     * We first set a BREAKPOINT event to suspend the debuggee. Once we
39     * hit the breakpoint, we set a METHOD_ENTRY event on the debuggee class
40     * to cause a full deoptimization of the stack and resume it.
41     * Finally, we wait for the debuggee to send us the result of the test
42     * (an integer as a string) and check this is the expected result.
43     */
44    public void testDeoptimizationWithExceptionHandling_001() {
45        logWriter.println("testDeoptimizationWithExceptionHandling_001 starts");
46        runTestDeoptimizationWithExceptionHandling(false);
47        logWriter.println("testDeoptimizationWithExceptionHandling_001 ends");
48    }
49
50    /**
51     * This tests checks we properly handle exception event when we fully
52     * deoptimize the stack and are able to receive EXCEPTION event for the
53     * thrown exception.
54     * We first set a BREAKPOINT event to suspend the debuggee. Once we
55     * hit the breakpoint, we set a METHOD_ENTRY event on the debuggee class
56     * to cause a full deoptimization of the stack and an EXCEPTION event
57     * to check we do suspend the debuggee for the thrown exception, and
58     * we resume the debuggee.
59     * Then we wait for the EXCEPTION event to be posted and resume the
60     * debuggee again.
61     * Finally, we wait for the debuggee to send us the result of the test
62     * (an integer as a string) and check this is the expected result.
63     */
64    public void testDeoptimizationWithExceptionHandling_002() {
65        logWriter.println("testDeoptimizationWithExceptionHandling_002 starts");
66        runTestDeoptimizationWithExceptionHandling(true);
67        logWriter.println("testDeoptimizationWithExceptionHandling_002 ends");
68    }
69
70    private void runTestDeoptimizationWithExceptionHandling(boolean withExceptionEvent) {
71        // Suspend debuggee on a breakpoint.
72        stopOnBreakpoint();
73
74        // Request MethodEntry event to cause full deoptimization of the debuggee.
75        installMethodEntry();
76
77        int exceptionRequestID = -1;
78        if (withExceptionEvent) {
79            // Request Exception event to test we suspend for this event during deoptimization.
80            exceptionRequestID = requestExceptionEvent();
81        }
82
83        // Resume the debuggee from the breakpoint.
84        debuggeeWrapper.vmMirror.resume();
85
86        if (exceptionRequestID != -1) {
87            // Wait for the Exception event.
88            waitForExceptionEvent(exceptionRequestID);
89
90            // Resume the debuggee from the exception.
91            debuggeeWrapper.vmMirror.resume();
92        }
93
94        // Wait for result from debuggee
95        String resultAsString = synchronizer.receiveMessage();
96        int result = Integer.parseInt(resultAsString);
97
98        assertEquals("Incorrect result",
99                     DeoptimizationWithExceptionHandlingDebuggee.SUCCESS_RESULT, result);
100    }
101
102    private void stopOnBreakpoint() {
103        // Wait for debuggee to start.
104        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
105
106        long debuggeeClassID = getClassIDBySignature(getDebuggeeClassSignature());
107        int requestID = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(debuggeeClassID,
108                                                                            "breakpointMethod");
109
110        // Continue debuggee.
111        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
112
113        // Wait for breakpoint.
114        debuggeeWrapper.vmMirror.waitForBreakpoint(requestID);
115
116        // Remove breakpoint.
117        debuggeeWrapper.vmMirror.clearBreakpoint(requestID);
118    }
119
120    private void installMethodEntry() {
121        ReplyPacket replyPacket = debuggeeWrapper.vmMirror.setMethodEntry(getDebuggeeClassName());
122        replyPacket.getNextValueAsInt();  // unused 'requestID'
123        assertAllDataRead(replyPacket);
124    }
125
126    private int requestExceptionEvent() {
127        final String exceptionClassSignature = "Ljava/lang/NullPointerException;";
128        ReplyPacket replyPacket =
129                debuggeeWrapper.vmMirror.setException(exceptionClassSignature, true, false);
130        int requestID = replyPacket.getNextValueAsInt();
131        assertAllDataRead(replyPacket);
132        return requestID;
133    }
134
135    private void waitForExceptionEvent(int requestID) {
136        final byte eventKind = JDWPConstants.EventKind.EXCEPTION;
137        EventPacket event = debuggeeWrapper.vmMirror.receiveCertainEvent(eventKind);
138
139        ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(event);
140        assertNotNull("Expected an exception event", parsedEvents);
141        assertEquals("Expected only one event", 1, parsedEvents.length);
142        assertEquals("Not the excepted event", requestID, parsedEvents[0].getRequestID());
143
144        // Clear the event
145        debuggeeWrapper.vmMirror.clearEvent(eventKind, requestID);
146    }
147}
148