Skip to content

Commit fd32ce3

Browse files
committed
[GR-69428] Handle suspendHere() in internal code.
PullRequest: graal/22073
2 parents 9df1ea1 + b490a68 commit fd32ce3

File tree

2 files changed

+158
-5
lines changed

2 files changed

+158
-5
lines changed

truffle/src/com.oracle.truffle.api.debug.test/src/com/oracle/truffle/api/debug/test/DebuggerSessionTest.java

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -71,21 +71,30 @@
7171
import org.junit.Assert;
7272
import org.junit.Test;
7373

74+
import com.oracle.truffle.api.CallTarget;
7475
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
76+
import com.oracle.truffle.api.RootCallTarget;
77+
import com.oracle.truffle.api.Truffle;
78+
import com.oracle.truffle.api.TruffleLanguage;
7579
import com.oracle.truffle.api.debug.Breakpoint;
7680
import com.oracle.truffle.api.debug.Debugger;
7781
import com.oracle.truffle.api.debug.DebuggerSession;
7882
import com.oracle.truffle.api.debug.SuspendedCallback;
7983
import com.oracle.truffle.api.debug.SuspendedEvent;
8084
import com.oracle.truffle.api.debug.SuspensionFilter;
85+
import com.oracle.truffle.api.frame.FrameDescriptor;
86+
import com.oracle.truffle.api.frame.FrameSlotKind;
8187
import com.oracle.truffle.api.frame.VirtualFrame;
8288
import com.oracle.truffle.api.instrumentation.EventContext;
8389
import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
90+
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
91+
import com.oracle.truffle.api.instrumentation.ProbeNode;
8492
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
8593
import com.oracle.truffle.api.instrumentation.StandardTags;
8694
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
8795
import com.oracle.truffle.api.instrumentation.test.InstrumentationTestLanguage;
8896
import com.oracle.truffle.api.nodes.Node;
97+
import com.oracle.truffle.api.nodes.RootNode;
8998
import com.oracle.truffle.api.source.SourceSection;
9099
import com.oracle.truffle.api.test.GCUtils;
91100
import com.oracle.truffle.api.test.polyglot.ProxyLanguage;
@@ -311,6 +320,149 @@ public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwa
311320
}
312321
}
313322

323+
@Test
324+
public void testSuspendHereFromLanguage() {
325+
String text = "suspendHereSource";
326+
Source source = Source.create(ProxyLanguage.ID, text);
327+
try (DebuggerSession session = startSession()) {
328+
ProxyLanguage.setDelegate(new SuspendDebuggerFromLanguage(session, false));
329+
330+
startEval(source);
331+
expectSuspended((SuspendedEvent event) -> {
332+
Assert.assertEquals(text, event.getSourceSection().getCharacters().toString());
333+
});
334+
expectDone();
335+
}
336+
}
337+
338+
@Test
339+
public void testSuspendHereFromLanguageInternalSource() {
340+
String text = "suspendHereSource";
341+
Source source = Source.newBuilder(ProxyLanguage.ID, text, "name").internal(true).buildLiteral();
342+
try (DebuggerSession session = startSession()) {
343+
ProxyLanguage.setDelegate(new SuspendDebuggerFromLanguage(session, false));
344+
345+
startEval(source);
346+
expectSuspended((SuspendedEvent event) -> {
347+
Assert.assertEquals(text, event.getSourceSection().getCharacters().toString());
348+
Assert.assertTrue(event.getSourceSection().getSource().isInternal());
349+
});
350+
expectDone();
351+
}
352+
}
353+
354+
@Test
355+
public void testSuspendHereFromLanguageInternalRoot() {
356+
String text = "suspendHereSource";
357+
Source source = Source.newBuilder(ProxyLanguage.ID, text, "name").buildLiteral();
358+
try (DebuggerSession session = startSession()) {
359+
ProxyLanguage.setDelegate(new SuspendDebuggerFromLanguage(session, true));
360+
361+
startEval(source);
362+
expectSuspended((SuspendedEvent event) -> {
363+
Assert.assertEquals(text, event.getSourceSection().getCharacters().toString());
364+
Assert.assertFalse(event.getSourceSection().getSource().isInternal());
365+
Assert.assertTrue(Truffle.getRuntime().iterateFrames((frameInstance) -> {
366+
RootNode root = ((RootCallTarget) frameInstance.getCallTarget()).getRootNode();
367+
return root.isInternal();
368+
}));
369+
});
370+
expectDone();
371+
}
372+
}
373+
374+
public static class SuspendDebuggerFromLanguage extends ProxyLanguage {
375+
376+
private final DebuggerSession session;
377+
private final boolean forceRootInternal;
378+
379+
SuspendDebuggerFromLanguage(DebuggerSession session, boolean forceRootInternal) {
380+
this.session = session;
381+
this.forceRootInternal = forceRootInternal;
382+
}
383+
384+
@Override
385+
protected CallTarget parse(ParsingRequest request) throws Exception {
386+
return new SuspendDebuggerRoot(languageInstance, session, request.getSource(), forceRootInternal).getCallTarget();
387+
}
388+
389+
static class SuspendDebuggerRoot extends RootNode {
390+
391+
private final DebuggerSession session;
392+
private final boolean forceRootInternal;
393+
@Node.Child private SuspendDebugNode statement;
394+
395+
SuspendDebuggerRoot(TruffleLanguage<?> language, DebuggerSession session, com.oracle.truffle.api.source.Source source, boolean forceRootInternal) {
396+
super(language, createFrameDescriptor());
397+
this.session = session;
398+
this.forceRootInternal = forceRootInternal;
399+
this.statement = new SuspendDebugNode(source.createSection(1));
400+
}
401+
402+
private static FrameDescriptor createFrameDescriptor() {
403+
FrameDescriptor.Builder fdb = FrameDescriptor.newBuilder();
404+
fdb.addSlot(FrameSlotKind.Object, "session", null);
405+
return fdb.build();
406+
}
407+
408+
@Override
409+
public Object execute(VirtualFrame frame) {
410+
frame.setObject(0, session);
411+
return statement.execute(frame);
412+
}
413+
414+
@Override
415+
public SourceSection getSourceSection() {
416+
return statement.getSourceSection();
417+
}
418+
419+
@Override
420+
public boolean isInternal() {
421+
if (!forceRootInternal) {
422+
return super.isInternal();
423+
} else {
424+
return true;
425+
}
426+
}
427+
428+
}
429+
430+
static class SuspendDebugNode extends Node implements InstrumentableNode {
431+
432+
private final SourceSection section;
433+
434+
SuspendDebugNode(SourceSection section) {
435+
this.section = section;
436+
}
437+
438+
@Override
439+
public SourceSection getSourceSection() {
440+
return section;
441+
}
442+
443+
public Object execute(VirtualFrame frame) {
444+
DebuggerSession session = (DebuggerSession) frame.getObject(0);
445+
suspendHere(session);
446+
return 1;
447+
}
448+
449+
@TruffleBoundary
450+
private void suspendHere(DebuggerSession session) {
451+
session.suspendHere(this);
452+
}
453+
454+
@Override
455+
public boolean isInstrumentable() {
456+
return true;
457+
}
458+
459+
@Override
460+
public WrapperNode createWrapper(ProbeNode probe) {
461+
throw new UnsupportedOperationException();
462+
}
463+
}
464+
}
465+
314466
@Test
315467
public void testSuspendThread1() {
316468
Source testSource = testSource("ROOT(\n" +

truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,13 @@ public boolean suspendHere(Node node) {
440440

441441
SuspendContextAndFrame result = Truffle.getRuntime().iterateFrames((frameInstance) -> {
442442
RootNode root = ((RootCallTarget) frameInstance.getCallTarget()).getRootNode();
443-
if (!includeInternal) {
444-
if (root.isInternal()) {
445-
return null;
446-
}
443+
if (nodeRoot == null && !includeInternal && root.isInternal()) {
444+
return null;
447445
}
448446
if (nodeRoot != null && nodeRoot != root) {
447+
if (!includeInternal && root.isInternal()) {
448+
return null;
449+
}
449450
throw new IllegalArgumentException(String.format("The node %s belongs to a root %s, which is different from the current root %s.", node, nodeRoot, root));
450451
}
451452
Node callNode = frameInstance.getInstrumentableCallNode();

0 commit comments

Comments
 (0)