From 967f95d0e2cbad3db68944afdb0e374bf3d6b861 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Tue, 3 Mar 2026 15:05:34 +0100 Subject: [PATCH 1/5] AlwaysHalt tag on call to breakpoint built-in --- .../python/compiler/bytecode_dsl/RootNodeCompiler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index 5ec45f3742..2146140e71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -57,6 +57,7 @@ import static com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompilerUtils.hasDefaultArgs; import static com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompilerUtils.hasDefaultKwargs; import static com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompilerUtils.len; +import static com.oracle.graal.python.nodes.BuiltinNames.J_BREAKPOINT; import static com.oracle.graal.python.nodes.SpecialAttributeNames.J___CLASS__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.J___TYPE_PARAMS__; import static com.oracle.graal.python.util.PythonUtils.codePointsToInternedTruffleString; @@ -156,6 +157,7 @@ import com.oracle.truffle.api.bytecode.BytecodeParser; import com.oracle.truffle.api.bytecode.BytecodeRootNodes; import com.oracle.truffle.api.bytecode.serialization.BytecodeSerializer; +import com.oracle.truffle.api.debug.DebuggerTags; import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; @@ -1674,7 +1676,13 @@ private void emitNameOperation(String name, NameOperation op, Builder b) { } } else if (uses.contains(DefUse.GlobalImplicit)) { if (scope.isFunction()) { - emitNameGlobalOperation(mangled, op, b, true); + if (mangled.equals(J_BREAKPOINT)) { + b.beginTag(DebuggerTags.AlwaysHalt.class); + emitNameGlobalOperation(mangled, op, b, true); + b.endTag(DebuggerTags.AlwaysHalt.class); + } else { + emitNameGlobalOperation(mangled, op, b, true); + } return; } } else if (uses.contains(DefUse.GlobalExplicit)) { From a31f4f2f02571674e57f4cfe100a7173e0e49297 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Wed, 4 Mar 2026 11:22:38 +0100 Subject: [PATCH 2/5] moved logic to emitCall() to not break on breakpoint when not called --- .../bytecode_dsl/RootNodeCompiler.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index 2146140e71..c5e24dbdce 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -1676,13 +1676,7 @@ private void emitNameOperation(String name, NameOperation op, Builder b) { } } else if (uses.contains(DefUse.GlobalImplicit)) { if (scope.isFunction()) { - if (mangled.equals(J_BREAKPOINT)) { - b.beginTag(DebuggerTags.AlwaysHalt.class); - emitNameGlobalOperation(mangled, op, b, true); - b.endTag(DebuggerTags.AlwaysHalt.class); - } else { - emitNameGlobalOperation(mangled, op, b, true); - } + emitNameGlobalOperation(mangled, op, b, true); return; } } else if (uses.contains(DefUse.GlobalExplicit)) { @@ -2196,8 +2190,18 @@ private void emitCall(ExprTy func, ExprTy[] args, KeywordTy[] keywords) { } else { assert len(keywords) == 0; + boolean isBreakpoint = func instanceof ExprTy.Name && ((ExprTy.Name) func).id.equals(J_BREAKPOINT); + + if (isBreakpoint) { + b.beginTag(DebuggerTags.AlwaysHalt.class); + } + func.accept(this); // callable visitArguments(func, args, numArgs); + + if (isBreakpoint) { + b.endTag(DebuggerTags.AlwaysHalt.class); + } } } From 4b98a7ad364bcd8564a4dd0dba3f2f7593d604c7 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Wed, 4 Mar 2026 15:29:43 +0100 Subject: [PATCH 3/5] adding testInlineEvaluationBreakpointBuiltin --- .../python/test/debug/PythonDebugTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java index f6cca17770..0772adfba8 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java @@ -600,6 +600,31 @@ public void testSourceFileURI() throws Throwable { deleteRecursively(tempDir); } } + + @Test + public void testInlineEvaluationBreakpointBuiltin() throws Throwable { + final Source source = Source.newBuilder("python", """ + a = 1 + breakpoint() + b = 2 + breakpoint # not invoking, therefore no breakpoint inserted + """, "test_inline.py").buildLiteral(); + + try (DebuggerSession session = tester.startSession()) { + session.install(Breakpoint.newBuilder(DebuggerTester.getSourceImpl(source)).lineIs(1).build()); + session.install(Breakpoint.newBuilder(DebuggerTester.getSourceImpl(source)).lineIs(3).build()); + tester.startEval(source); + expectSuspended((SuspendedEvent event) -> { + event.prepareContinue(); + }); + expectSuspended((SuspendedEvent event) -> { + event.prepareContinue(); + }); + expectSuspended((SuspendedEvent event) -> { + event.prepareContinue(); + }); + } + } private void expectSuspended(SuspendedCallback callback) { tester.expectSuspended(callback); From 1adc60601e362ba05feda2090fed809a99264bd0 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Wed, 4 Mar 2026 16:22:21 +0100 Subject: [PATCH 4/5] checking line for each breakpoint --- .../oracle/graal/python/test/debug/PythonDebugTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java index 0772adfba8..e82d4cbe6e 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java @@ -600,7 +600,7 @@ public void testSourceFileURI() throws Throwable { deleteRecursively(tempDir); } } - + @Test public void testInlineEvaluationBreakpointBuiltin() throws Throwable { final Source source = Source.newBuilder("python", """ @@ -615,12 +615,18 @@ public void testInlineEvaluationBreakpointBuiltin() throws Throwable { session.install(Breakpoint.newBuilder(DebuggerTester.getSourceImpl(source)).lineIs(3).build()); tester.startEval(source); expectSuspended((SuspendedEvent event) -> { + DebugStackFrame frame = event.getTopStackFrame(); + assertEquals(1, frame.getSourceSection().getStartLine()); event.prepareContinue(); }); expectSuspended((SuspendedEvent event) -> { + DebugStackFrame frame = event.getTopStackFrame(); + assertEquals(2, frame.getSourceSection().getStartLine()); event.prepareContinue(); }); expectSuspended((SuspendedEvent event) -> { + DebugStackFrame frame = event.getTopStackFrame(); + assertEquals(3, frame.getSourceSection().getStartLine()); event.prepareContinue(); }); } From b573a322e36cf58c8bebdd4e9ba306378d687521 Mon Sep 17 00:00:00 2001 From: Octave Larose Date: Wed, 4 Mar 2026 17:42:30 +0100 Subject: [PATCH 5/5] eclipse formatter pass --- .../graal/python/test/debug/PythonDebugTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java index e82d4cbe6e..41140d446a 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java @@ -604,11 +604,11 @@ public void testSourceFileURI() throws Throwable { @Test public void testInlineEvaluationBreakpointBuiltin() throws Throwable { final Source source = Source.newBuilder("python", """ - a = 1 - breakpoint() - b = 2 - breakpoint # not invoking, therefore no breakpoint inserted - """, "test_inline.py").buildLiteral(); + a = 1 + breakpoint() + b = 2 + breakpoint # not invoking, therefore no breakpoint inserted + """, "test_inline.py").buildLiteral(); try (DebuggerSession session = tester.startSession()) { session.install(Breakpoint.newBuilder(DebuggerTester.getSourceImpl(source)).lineIs(1).build());