Skip to content

Commit

Permalink
Allow activation of REPL at end of given function name
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach committed Aug 16, 2024
1 parent eb3b76e commit 454804f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
import com.oracle.truffle.api.debug.DebuggerTags;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.EventBinding;
import com.oracle.truffle.api.instrumentation.EventContext;
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
import com.oracle.truffle.api.instrumentation.Instrumenter;
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.nodes.RootNode;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.enso.compiler.context.FramePointer;
import org.enso.interpreter.node.EnsoRootNode;
import org.enso.interpreter.node.expression.builtin.debug.DebugBreakpointNode;
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
import org.enso.interpreter.node.expression.debug.CaptureResultScopeNode;
Expand Down Expand Up @@ -65,7 +70,7 @@ protected void onCreate(Env env) {
ctx ->
ctx.getInstrumentedNode() instanceof DebugBreakpointNode
? new ReplExecutionEventNodeImpl(
ctx, handler, env.getLogger(ReplExecutionEventNodeImpl.class))
false, ctx, handler, env.getLogger(ReplExecutionEventNodeImpl.class))
: null);
} else {
env.getLogger(ReplDebuggerInstrument.class)
Expand All @@ -80,23 +85,16 @@ protected void onCreate(Env env) {
throw new RuntimeException(e);
}
}
if (!"".equals(env.getOptions().get(FN_OPTION))) {
SourceSectionFilter filter =
SourceSectionFilter.newBuilder().tagIs(DebuggerTags.AlwaysHalt.class).build();

var replAtMethodName = env.getOptions().get(FN_OPTION);
if (!"".equals(replAtMethodName)) {
DebuggerMessageHandler handler = new DebuggerMessageHandler();
try {
MessageEndpoint client = env.startServer(URI.create(DebugServerInfo.URI), handler);
if (client != null) {
handler.setClient(client);
Instrumenter instrumenter = env.getInstrumenter();
instrumenter.attachExecutionEventFactory(
filter,
ctx ->
ctx.getInstrumentedNode() instanceof DebugBreakpointNode
? new ReplExecutionEventNodeImpl(
ctx, handler, env.getLogger(ReplExecutionEventNodeImpl.class))
: null);
var replAtMethod = new AtTheEndOfFirstMethod(handler, env, instrumenter);
replAtMethod.activate(replAtMethodName);
} else {
env.getLogger(ReplDebuggerInstrument.class)
.warning("ReplDebuggerInstrument was initialized, " + "but no client connected");
Expand Down Expand Up @@ -132,12 +130,17 @@ private static class ReplExecutionEventNodeImpl extends ExecutionEventNode
private EventContext eventContext;
private DebuggerMessageHandler handler;
private TruffleLogger logger;
private final boolean atExit;

private ReplExecutionEventNodeImpl(
EventContext eventContext, DebuggerMessageHandler handler, TruffleLogger logger) {
boolean atExit,
EventContext eventContext,
DebuggerMessageHandler handler,
TruffleLogger logger) {
this.eventContext = eventContext;
this.handler = handler;
this.logger = logger;
this.atExit = atExit;
}

private Object getValue(MaterializedFrame frame, FramePointer ptr) {
Expand Down Expand Up @@ -216,7 +219,14 @@ protected void onEnter(VirtualFrame frame) {
// Note [Safe Access to State in the Debugger Instrument]
monadicState = Function.ArgumentsHelper.getState(frame.getArguments());
nodeState = new ReplExecutionEventNodeState(lastReturn, lastScope);
startSession();
startSessionImpl();
}

@Override
public void onReturnValue(VirtualFrame frame, Object result) {
if (atExit) {
startSession(getRootNode(), frame);
}
}

/* Note [Safe Access to State in the Debugger Instrument]
Expand All @@ -240,8 +250,23 @@ protected Object onUnwind(VirtualFrame frame, Object info) {
return nodeState.getLastReturn();
}

private void startSession(RootNode root, VirtualFrame frame) {
CallerInfo lastScope = Function.ArgumentsHelper.getCallerInfo(frame.getArguments());
if (lastScope == null && root instanceof EnsoRootNode enso) {
lastScope =
new CallerInfo(frame.materialize(), enso.getLocalScope(), enso.getModuleScope());
}
if (lastScope != null) {
var lastReturn = EnsoContext.get(this).getNothing();
// Note [Safe Access to State in the Debugger Instrument]
monadicState = Function.ArgumentsHelper.getState(frame.getArguments());
nodeState = new ReplExecutionEventNodeState(lastReturn, lastScope);
startSessionImpl();
}
}

@CompilerDirectives.TruffleBoundary
private void startSession() {
private void startSessionImpl() {
if (handler.hasClient()) {
handler.startSession(this);
} else {
Expand Down Expand Up @@ -277,4 +302,35 @@ CallerInfo getLastScope() {
}
}
}

private final class AtTheEndOfFirstMethod implements ExecutionEventNodeFactory {
private final Instrumenter instr;
private final DebuggerMessageHandler handler;
private final TruffleInstrument.Env env;
private EventBinding<?> firstMethod;

AtTheEndOfFirstMethod(DebuggerMessageHandler h, TruffleInstrument.Env env, Instrumenter instr) {
this.instr = instr;
this.handler = h;
this.env = env;
}

final void activate(String methodName) {
var b = SourceSectionFilter.newBuilder();
b.tagIs(StandardTags.RootBodyTag.class);
b.rootNameIs(
(n) -> {
return methodName.equals(n);
});
var anyMethod = b.build();
this.firstMethod = instr.attachExecutionEventFactory(anyMethod, this);
}

@Override
public ExecutionEventNode create(EventContext ctx) {
firstMethod.dispose();
var log = env.getLogger(ReplExecutionEventNodeImpl.class);
return new ReplExecutionEventNodeImpl(true, ctx, handler, log);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DebugServerTest

override def contextModifiers: Option[Context#Builder => Context#Builder] =
Some(b => {
b.option(DebugServerInfo.FN_OPTION, "main")
b.option(DebugServerInfo.FN_OPTION, "Test.main")
})

override def specify(implicit
Expand All @@ -27,7 +27,7 @@ class DebugServerTest
"""
|import Standard.Base.Runtime.Debug
|
|main = Debug.breakpoint
|main = "hi"
|""".stripMargin
setSessionManager(executor => executor.exit())
eval(code)
Expand All @@ -36,13 +36,11 @@ class DebugServerTest
"be able to execute arbitrary code in the caller scope" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Data.Numbers
|
|main =
| x = 1
| y = 2
| Debug.breakpoint
|""".stripMargin
var evalResult: Either[Exception, ObjectRepresentation] =
null
Expand All @@ -57,11 +55,10 @@ class DebugServerTest
"be able to define its local variables" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Data.Numbers
|
|main =
| x = 10
| Debug.breakpoint
|""".stripMargin
setSessionManager { executor =>
executor.evaluate("y = x + 1")
Expand All @@ -75,14 +72,12 @@ class DebugServerTest
"be able to list local variables in its scope" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Data.Numbers
|
|main =
| x = 10
| y = 20
| z = x + y
|
| Debug.breakpoint
|""".stripMargin
var scopeResult: Map[String, ObjectRepresentation] = Map()
setSessionManager { executor =>
Expand All @@ -100,14 +95,12 @@ class DebugServerTest
"be able to list bindings it has created" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Data.Numbers
|
|main =
| x = 10
| y = 20
| z = x + y
|
| Debug.breakpoint
|""".stripMargin
var scopeResult: Map[String, ObjectRepresentation] = Map()
setSessionManager { executor =>
Expand All @@ -126,10 +119,10 @@ class DebugServerTest
"handle errors gracefully" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Data.Numbers
|
|main =
| Debug.breakpoint
| "hi"
|""".stripMargin
var evalResult: Either[Exception, ObjectRepresentation] =
null
Expand Down Expand Up @@ -167,11 +160,10 @@ class DebugServerTest
"attach language stack traces to the exception" in {
val code =
"""
|import Standard.Base.Runtime.Debug
|import Standard.Base.Panic.Panic
|
|main =
| Debug.breakpoint
| "hi"
|""".stripMargin
var evalResult: Either[Exception, ObjectRepresentation] =
null
Expand All @@ -188,7 +180,7 @@ class DebugServerTest

val traceMethodNames = lastException.getStackTrace.map(_.getMethodName)
traceMethodNames should contain("Panic.throw")
traceMethodNames should contain("Debug.breakpoint")
traceMethodNames should contain("Test::Test::main")
}
}
}

0 comments on commit 454804f

Please sign in to comment.