E5EE Display the method return value when stepping out by testforstephen · Pull Request #336 · microsoft/java-debug · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* Copyright (c) 2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core;

import com.sun.jdi.Method;
import com.sun.jdi.Value;

public class JdiMethodResult {
public Method method;
public Value value;

public JdiMethodResult(Method method, Value value) {
this.method = method;
this.value = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
public class AdapterUtils {
private static final String OS_NAME = System.getProperty("os.name", "").toLowerCase();
private static final Pattern ENCLOSING_CLASS_REGEX = Pattern.compile("^([^\\$]*)");
public static final boolean isWin = isWindows();
public static final boolean isMac = OS_NAME.contains("mac") || OS_NAME.contains("darwin");

/**
* Check if the OS is windows or not.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -61,6 +61,7 @@ public class DebugAdapterContext implements IDebugAdapterContext {
private IStackFrameManager stackFrameManager = new StackFrameManager();
private IExceptionManager exceptionManager = new ExceptionManager();
private IBreakpointManager breakpointManager = new BreakpointManager();
private IStepResultManager stepResultManager = new StepResultManager();

public DebugAdapterContext(IProtocolServer server, IProviderContext providerContext) {
this.providerContext = providerContext;
Expand Down Expand Up @@ -320,4 +321,9 @@ public IExceptionManager getExceptionManager() {
public IBreakpointManager getBreakpointManager() {
return breakpointManager;
}

@Override
public IStepResultManager getStepResultManager() {
return stepResultManager;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -126,4 +126,6 @@ public interface IDebugAdapterContext {
IExceptionManager getExceptionManager();

IBreakpointManager getBreakpointManager();

IStepResultManager getStepResultManager();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter;

import com.microsoft.java.debug.core.JdiMethodResult;

public interface IStepResultManager {
JdiMethodResult setMethodResult(long threadId, JdiMethodResult methodResult);

JdiMethodResult getMethodResult(long threadId);

JdiMethodResult removeMethodResult(long threadId);

void removeAllMethodResults();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.microsoft.java.debug.core.JdiMethodResult;

public class StepResultManager implements IStepResultManager {
private Map<Long, JdiMethodResult> methodResults = Collections.synchronizedMap(new HashMap<>());

@Override
public JdiMethodResult setMethodResult(long threadId, JdiMethodResult methodResult) {
return this.methodResults.put(threadId, methodResult);
}

@Override
public JdiMethodResult getMethodResult(long threadId) {
return this.methodResults.get(threadId);
}

@Override
public JdiMethodResult removeMethodResult(long threadId) {
return this.methodResults.remove(threadId);
}

@Override
public void removeAllMethodResults() {
this.methodResults.clear();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand All @@ -21,6 +21,7 @@
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.JdiExceptionReference;
import com.microsoft.java.debug.core.JdiMethodResult;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
Expand All @@ -34,11 +35,20 @@
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VoidValue;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.ExceptionEvent;
import com.sun.jdi.event.LocatableEvent;
import com.sun.jdi.event.MethodExitEvent;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.MethodExitRequest;
import com.sun.jdi.request.StepRequest;

import io.reactivex.disposables.Disposable;
Expand All @@ -61,6 +71,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
ThreadReference thread = DebugUtility.getThread(context.getDebugSession(), threadId);
if (thread != null) {
JdiExceptionReference exception = context.getExceptionManager().removeException(threadId);
context.getStepResultManager().removeMethodResult(threadId);
try {
ThreadState threadState = new ThreadState();
threadState.threadId = threadId;
Expand All @@ -69,7 +80,9 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
threadState.stepLocation = getTopFrame(thread).location();
threadState.eventSubscription = context.getDebugSession().getEventHub().events()
.filter(debugEvent -> (debugEvent.event instanceof StepEvent && debugEvent.event.request().equals(threadState.pendingStepRequest))
|| debugEvent.event instanceof BreakpointEvent)
|| (debugEvent.event instanceof MethodExitEvent && debugEvent.event.request().equals(threadState.pendingMethodExitRequest))
|| debugEvent.event instanceof BreakpointEvent
|| debugEvent.event instanceof ExceptionEvent)
.subscribe(debugEvent -> {
handleDebugEvent(debugEvent, context.getDebugSession(), context, threadState);
});
Expand All @@ -86,6 +99,24 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null);
}
threadState.pendingStepRequest.enable();

MethodExitRequest methodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest();
methodExitRequest.addThreadFilter(thread);
methodExitRequest.addClassFilter(threadState.stepLocation.declaringType());
if (thread.virtualMachine().canUseInstanceFilters()) {
try {
ObjectReference thisObject = getTopFrame(thread).thisObject();
if (thisObject != null) {
methodExitRequest.addInstanceFilter(thisObject);
}
} catch (Exception e) {
// ignore
}
}
methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
threadState.pendingMethodExitRequest = methodExitRequest;
methodExitRequest.enable();

DebugUtility.resumeThread(thread);

ThreadsRequestHandler.checkThreadRunningAndRecycleIds(thread, context);
Expand Down Expand Up @@ -116,19 +147,18 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
Event event = debugEvent.event;

// When a breakpoint occurs, abort any pending step requests from the same thread.
if (event instanceof BreakpointEvent) {
long threadId = ((BreakpointEvent) event).thread().uniqueID();
if (event instanceof BreakpointEvent || event instanceof ExceptionEvent) {
long threadId = ((LocatableEvent) event).thread().uniqueID();
if (threadId == threadState.threadId && threadState.pendingStepRequest != null) {
DebugUtility.deleteEventRequestSafely(debugSession.getVM().eventRequestManager(), threadState.pendingStepRequest);
threadState.pendingStepRequest = null;
threadState.deleteStepRequests(debugSession.getVM().eventRequestManager());
context.getStepResultManager().removeMethodResult(threadId);
if (threadState.eventSubscription != null) {
threadState.eventSubscription.dispose();
}
}
} else if (event instanceof StepEvent) {
ThreadReference thread = ((StepEvent) event).thread();
DebugUtility.deleteEventRequestSafely(thread.virtualMachine().eventRequestManager(), threadState.pendingStepRequest);
threadState.pendingStepRequest = null;
threadState.deleteStepRequests(debugSession.getVM().eventRequestManager());
if (isStepFiltersConfigured(context.getStepFilters())) {
try {
if (threadState.pendingStepType == Command.STEPIN) {
Expand Down Expand Up @@ -156,6 +186,19 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
}
context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID()));
debugEvent.shouldResume = false;
} else if (event instanceof MethodExitEvent) {
MethodExitEvent methodExitEvent = (MethodExitEvent) event;
long threadId = methodExitEvent.thread().uniqueID();
if (threadId == threadState.threadId && methodExitEvent.method().equals(threadState.stepLocation.method())) {
Value returnValue = methodExitEvent.returnValue();
if (returnValue instanceof VoidValue) {
context.getStepResultManager().removeMethodResult(threadId);
} else {
JdiMethodResult methodResult = new JdiMethodResult(methodExitEvent.method(), returnValue);
context.getStepResultManager().setMethodResult(threadId, methodResult);
}
}
debugEvent.shouldResume = true;
}
}

Expand Down Expand Up @@ -232,8 +275,16 @@ class ThreadState {
long threadId = -1;
Command pendingStepType;
StepRequest pendingStepRequest = null;
MethodExitRequest pendingMethodExitRequest = null;
int stackDepth = -1;
Location stepLocation = null;
Disposable eventSubscription = null;

public void deleteStepRequests(EventRequestManager manager) {
DebugUtility.deleteEventRequestSafely(manager, this.pendingStepRequest);
DebugUtility.deleteEventRequestSafely(manager, this.pendingMethodExitRequest);
this.pendingMethodExitRequest = null;
this.pendingStepRequest = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ private CompletableFuture<Response> threads(Requests.ThreadsArguments arguments,
private CompletableFuture<Response> pause(Requests.PauseArguments arguments, Response response, IDebugAdapterContext context) {
ThreadReference thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId);
if (thread != null) {
context.getStepResultManager().removeMethodResult(arguments.threadId);
thread.suspend();
context.getProtocolServer().sendEvent(new Events.StoppedEvent("pause", arguments.threadId));
} else {
context.getStepResultManager().removeAllMethodResults();
context.getDebugSession().suspend();
context.getProtocolServer().sendEvent(new Events.StoppedEvent("pause", arguments.threadId, true));
}
Expand All @@ -113,11 +115,13 @@ private CompletableFuture<Response> resume(Requests.ContinueArguments arguments,
* be resumed (through ThreadReference#resume() or VirtualMachine#resume()) the same number of times it has been suspended.
*/
if (thread != null) {
context.getStepResultManager().removeMethodResult(arguments.threadId);
context.getExceptionManager().removeException(arguments.threadId);
allThreadsContinued = false;
DebugUtility.resumeThread(thread);
checkThreadRunningAndRecycleIds(thread, context);
} else {
context.getStepResultManager().removeAllMethodResults();
context.getExceptionManager().removeAllExceptions();
context.getDebugSession().resume();
context.getRecyclableIdPool().removeAllObjects();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017-2019 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -28,6 +28,7 @@

import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.JdiMethodResult;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
Expand Down Expand Up @@ -106,7 +107,13 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
ErrorCode.GET_VARIABLE_FAILURE);
}
try {
childrenList = VariableUtils.listLocalVariables(frame);
long threadId = stackFrameReference.getThread().uniqueID();
JdiMethodResult result = context.getStepResultManager().getMethodResult(threadId);
if (result != null) {
String returnIcon = (AdapterUtils.isWin || AdapterUtils.isMac) ? "⎯►" : "->";
childrenList.add(new Variable(returnIcon + result.method.name() + "()", result.value));
}
childrenList.addAll(VariableUtils.listLocalVariables(frame));
Variable thisVariable = VariableUtils.getThisVariable(frame);
if (thisVariable != null) {
childrenList.add(thisVariable);
Expand Down
0