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
Expand Up @@ -38,6 +38,7 @@
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.espresso.jdwp.impl.BreakpointInfo;
import com.oracle.truffle.espresso.jdwp.impl.ClassPrepareRequest;
import com.oracle.truffle.espresso.jdwp.impl.DebuggerCommand;
import com.oracle.truffle.espresso.jdwp.impl.DebuggerController;
import com.oracle.truffle.espresso.jdwp.impl.FieldBreakpointEvent;
import com.oracle.truffle.espresso.jdwp.impl.FieldBreakpointInfo;
Expand Down Expand Up @@ -530,7 +531,14 @@ public void stepCompleted(SteppingInfo info, CallFrame currentFrame) {
stream.writeByte(currentFrame.getTypeTag());
stream.writeLong(currentFrame.getClassId());
stream.writeLong(currentFrame.getMethodId());
long codeIndex = info.getStepOutBCI() != -1 ? info.getStepOutBCI() : currentFrame.getCodeIndex();
long codeIndex = currentFrame.getCodeIndex();
if (info.getStepKind() == DebuggerCommand.Kind.STEP_OUT) {
// Step out in Truffle is implemented on the callee exit, where the event's top
// stack frame is set to the caller frame. Hence, to avoid sending the code index
// from the caller location, we must fetch the next bci from the frame to pass the
// correct location.
codeIndex = context.getNextBCI(currentFrame.getRootNode(), currentFrame.getFrame());
}
stream.writeLong(codeIndex);
debuggerController.fine(() -> "Sending step completed event");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, 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
Expand All @@ -25,11 +25,7 @@
import java.util.concurrent.Callable;

public interface Commands {
void stepOver(Object thread, RequestFilter filter);

void stepInto(Object thread, RequestFilter filter);

void stepOut(Object thread, RequestFilter filter);
void step(Object thread, RequestFilter filter, DebuggerCommand.Kind stepKind);

Callable<Void> createLineBreakpointCommand(BreakpointInfo info);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, 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
Expand All @@ -22,9 +22,9 @@
*/
package com.oracle.truffle.espresso.jdwp.impl;

final class DebuggerCommand {
public final class DebuggerCommand {

enum Kind {
public enum Kind {
STEP_INTO,
STEP_OVER,
STEP_OUT,
Expand All @@ -37,21 +37,12 @@ enum Kind {
private final RequestFilter requestFilter;
private SourceLocation location;
private BreakpointInfo breakpointInfo;
private volatile boolean submitted;

DebuggerCommand(Kind kind, RequestFilter filter) {
this.kind = kind;
this.requestFilter = filter;
}

public boolean isSubmitted() {
return submitted;
}

public void markSubmitted() {
submitted = true;
}

void setSourceLocation(SourceLocation location) {
this.location = location;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, 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
Expand Down Expand Up @@ -58,19 +58,8 @@ public void closeSocket() {
}

@Override
public void stepInto(Object thread, RequestFilter filter) {
controller.setCommandRequestId(thread, filter.getRequestId(), filter.getSuspendPolicy(), false, false, DebuggerCommand.Kind.STEP_INTO);
}

@Override
public void stepOver(Object thread, RequestFilter filter) {
controller.setCommandRequestId(thread, filter.getRequestId(), filter.getSuspendPolicy(), false, false, DebuggerCommand.Kind.STEP_OVER);
}

@Override
public void stepOut(Object thread, RequestFilter filter) {
controller.setCommandRequestId(thread, filter.getRequestId(), filter.getSuspendPolicy(), false, false, DebuggerCommand.Kind.STEP_OUT);
controller.stepOut(filter);
public void step(Object thread, RequestFilter filter, DebuggerCommand.Kind stepKind) {
controller.setCommandRequestId(thread, filter.getRequestId(), filter.getSuspendPolicy(), false, false, stepKind);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, 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
Expand Down Expand Up @@ -397,33 +397,6 @@ public void clearBreakpoints() {
}
}

void stepOut(RequestFilter filter) {
Object thread = filter.getStepInfo().getGuestThread();
fine(() -> "STEP_OUT for thread: " + getThreadName(thread));

SuspendedInfo susp = suspendedInfos.get(thread);
if (susp != null && !(susp instanceof UnknownSuspendedInfo)) {
doStepOut(susp);
} else {
fine(() -> "not STEPPING OUT for thread: " + getThreadName(thread));
}
}

private void doStepOut(SuspendedInfo susp) {
assert susp != null && !(susp instanceof UnknownSuspendedInfo);
RootNode callerRoot = susp.getCallerRootNode();
int stepOutBCI = context.getNextBCI(callerRoot, susp.getCallerFrame());
SteppingInfo steppingInfo = commandRequestIds.get(susp.getThread());
if (steppingInfo != null && stepOutBCI != -1) {
// record the location that we'll land on after the step out completes
MethodVersionRef method = context.getMethodFromRootNode(callerRoot);
if (method != null) {
KlassRef klass = method.getMethod().getDeclaringKlassRef();
steppingInfo.setStepOutBCI(context.getIds().getIdAsLong(klass), context.getIds().getIdAsLong(method.getMethod()), stepOutBCI);
}
}
}

public void clearStepCommand(StepInfo stepInfo) {
commandRequestIds.remove(stepInfo.getGuestThread());
}
Expand Down Expand Up @@ -977,21 +950,21 @@ public void onSuspend(SuspendedEvent event) {
context.steppingInProgress(hostThread, false);
return;
}
CallFrame[] callFrames = createCallFrames(ids.getIdAsLong(currentThread), event.getStackFrames(), 1, steppingInfo);
CallFrame[] callFrames = createCallFrames(ids.getIdAsLong(currentThread), event.getStackFrames(), 1, false);
// get the top frame for checking instance filters
CallFrame callFrame = null;
if (callFrames.length > 0) {
callFrame = callFrames[0];
}
if (checkExclusionFilters(steppingInfo, event, currentThread, callFrame)) {
if (checkExclusionFilters(steppingInfo, event, callFrame)) {
fine(() -> "not suspending here: " + event.getSourceSection());
// continue stepping until completed
commandRequestIds.put(currentThread, steppingInfo);
return;
}
}

CallFrame[] callFrames = createCallFrames(ids.getIdAsLong(currentThread), event.getStackFrames(), -1, steppingInfo);
boolean isStepOut = steppingInfo != null && event.isStep() && steppingInfo.getStepKind() == DebuggerCommand.Kind.STEP_OUT;
CallFrame[] callFrames = createCallFrames(ids.getIdAsLong(currentThread), event.getStackFrames(), -1, isStepOut);
RootNode callerRootNode = callFrames.length > 1 ? callFrames[1].getRootNode() : null;

SuspendedInfo suspendedInfo = new SuspendedInfo(context, event, callFrames, currentThread, callerRootNode);
Expand All @@ -1014,8 +987,8 @@ public void onSuspend(SuspendedEvent event) {
result = checkForBreakpoints(event, jobs, currentThread, callFrames);
if (!result.breakpointHit) {
// no breakpoint
continueStepping(event, steppingInfo, currentThread);
commandRequestIds.put(currentThread, steppingInfo);
continueStepping(event, steppingInfo);
}
}
} else {
Expand Down Expand Up @@ -1159,10 +1132,10 @@ private boolean matchLocation(Pattern[] patterns, CallFrame callFrame) {
return false;
}

private boolean checkExclusionFilters(SteppingInfo info, SuspendedEvent event, Object thread, CallFrame frame) {
private boolean checkExclusionFilters(SteppingInfo info, SuspendedEvent event, CallFrame frame) {
if (info != null) {
if (isSingleSteppingSuspended()) {
continueStepping(event, info, thread);
continueStepping(event, info);
return true;
}
if (frame == null) {
Expand All @@ -1177,7 +1150,7 @@ private boolean checkExclusionFilters(SteppingInfo info, SuspendedEvent event, O
Object filterObject = context.getIds().fromId((int) requestFilter.getThisFilterId());
Object thisObject = frame.getThisValue();
if (filterObject != thisObject) {
continueStepping(event, info, thread);
continueStepping(event, info);
return true;
}
}
Expand All @@ -1186,15 +1159,15 @@ private boolean checkExclusionFilters(SteppingInfo info, SuspendedEvent event, O

if (klass != null && requestFilter.isKlassExcluded(klass)) {
// should not suspend here then, tell the event to keep going
continueStepping(event, info, thread);
continueStepping(event, info);
return true;
}
}
}
return false;
}

private void continueStepping(SuspendedEvent event, SteppingInfo steppingInfo, Object thread) {
private void continueStepping(SuspendedEvent event, SteppingInfo steppingInfo) {
switch (steppingInfo.getStepKind()) {
case STEP_INTO:
// stepping into unwanted code which was filtered
Expand All @@ -1205,17 +1178,14 @@ private void continueStepping(SuspendedEvent event, SteppingInfo steppingInfo, O
event.prepareStepOver(STEP_CONFIG);
break;
case STEP_OUT:
SuspendedInfo info = getSuspendedInfo(thread);
if (info != null && !(info instanceof UnknownSuspendedInfo)) {
doStepOut(info);
}
event.prepareStepOut(STEP_CONFIG);
break;
default:
break;
}
}

private CallFrame[] createCallFrames(long threadId, Iterable<DebugStackFrame> stackFrames, int frameLimit, SteppingInfo steppingInfo) {
private CallFrame[] createCallFrames(long threadId, Iterable<DebugStackFrame> stackFrames, int frameLimit, boolean isStepOut) {
LinkedList<CallFrame> list = new LinkedList<>();
int frameCount = 0;
for (DebugStackFrame frame : stackFrames) {
Expand Down Expand Up @@ -1247,10 +1217,10 @@ private CallFrame[] createCallFrames(long threadId, Iterable<DebugStackFrame> st
klassId = ids.getIdAsLong(klass);
methodId = ids.getIdAsLong(methodVersion.getMethod());
typeTag = TypeTag.getKind(klass);

// check if we have a dedicated step out code index on the top frame
if (frameCount == 0 && steppingInfo != null && steppingInfo.isStepOutFrame(methodId, klassId)) {
codeIndex = steppingInfo.getStepOutBCI();
if (isStepOut) {
// Truffle reports step out at the callers entry to the method, so we must fetch
// the BCI that follows to get the expected location within the frame.
codeIndex = context.getNextBCI(root, rawFrame);
} else {
codeIndex = context.getBCI(rawNode, rawFrame);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ public CommandResult registerEvent(Packet packet, Commands callback) {
Object thread = stepInfo.getGuestThread();
switch (stepInfo.getDepth()) {
case SteppingConstants.INTO:
callback.stepInto(thread, filter);
callback.step(thread, filter, DebuggerCommand.Kind.STEP_INTO);
break;
case SteppingConstants.OVER:
callback.stepOver(thread, filter);
callback.step(thread, filter, DebuggerCommand.Kind.STEP_OVER);
break;
case SteppingConstants.OUT:
callback.stepOut(thread, filter);
callback.step(thread, filter, DebuggerCommand.Kind.STEP_OUT);
break;
}
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
Expand All @@ -26,9 +26,6 @@ public final class SteppingInfo {

private final int requestId;
private final byte suspendPolicy;
private long stepOutBCI = -1;
private long stepOutMethodId = -1;
private long stepOutKlassId = -1;
private final boolean isPopFrames;
private final boolean isForceEarlyReturn;
private final DebuggerCommand.Kind stepKind;
Expand All @@ -50,16 +47,6 @@ public byte getSuspendPolicy() {
return suspendPolicy;
}

public void setStepOutBCI(long klassId, long methodId, long stepOutBCI) {
this.stepOutKlassId = klassId;
this.stepOutMethodId = methodId;
this.stepOutBCI = stepOutBCI;
}

public long getStepOutBCI() {
return stepOutBCI;
}

public boolean isPopFrames() {
return isPopFrames;
}
Expand All @@ -68,10 +55,6 @@ public boolean isForceEarlyReturn() {
return isForceEarlyReturn;
}

public boolean isStepOutFrame(long methodId, long klassId) {
return stepOutMethodId == methodId && stepOutKlassId == klassId;
}

public DebuggerCommand.Kind getStepKind() {
return stepKind;
}
Expand Down