diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index a5d042faf374d097999e16727ca2c7b1cb009846..378c3219ae107baa59c2e42256b5a50579516fdb 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -54,6 +54,7 @@ import com.oracle.truffle.r.nodes.builtin.helpers.DebugHandling; import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling; import com.oracle.truffle.r.nodes.control.AbstractLoopNode; import com.oracle.truffle.r.nodes.control.BlockNode; +import com.oracle.truffle.r.nodes.control.ForNode; import com.oracle.truffle.r.nodes.control.IfNode; import com.oracle.truffle.r.nodes.control.ReplacementDispatchNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; @@ -532,7 +533,9 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { return true; } else { // single statement block, variable parent - return parent instanceof FunctionDefinitionNode || parent instanceof IfNode || parent instanceof AbstractLoopNode; + // note: RepeatingNode is not a RSyntaxElement but the body of a loop is + // under the repeating node ! + return parent instanceof FunctionDefinitionNode || parent instanceof IfNode || parent instanceof AbstractLoopNode || ForNode.isLoopBody(node); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java index 80f96d66aa3d6895cfc9aee862ccb5d78126473b..e0f7a1713e607b557b34fc4e72f5a13a6582b1c4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java @@ -186,6 +186,7 @@ public class DebugHandling { @Override protected Void visit(RSyntaxFunction element) { + accept(element.getSyntaxBody()); return null; } }.accept(fdn); @@ -511,6 +512,9 @@ public class DebugHandling { } } + /** + * Handles the loop header and there is one instance registered for each loop. + */ private static class LoopStatementEventListener extends StatementEventListener { private boolean finishing; @@ -529,7 +533,7 @@ public class DebugHandling { @Override public void onEnter(EventContext context, VirtualFrame frame) { - if (!disabled()) { + if (!disabled() && context.getInstrumentedNode() == loopNode) { super.onEnter(context, frame); } } @@ -544,7 +548,7 @@ public class DebugHandling { @Override public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { - if (!disabled()) { + if (!disabled() && context.getInstrumentedNode() == loopNode) { CompilerDirectives.transferToInterpreter(); returnCleanup(); } @@ -552,7 +556,7 @@ public class DebugHandling { @Override public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { - if (!disabled()) { + if (!disabled() && context.getInstrumentedNode() == loopNode) { CompilerDirectives.transferToInterpreter(); returnCleanup(); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java index d50558d6209356a2ae00089374cf22c521aea35f..27575a9f1759ab5d3f3cec301318bc2c55573205 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.control; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.instrumentation.InstrumentableFactory.WrapperNode; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RepeatingNode; @@ -159,4 +160,16 @@ public final class ForNode extends AbstractLoopNode implements RSyntaxNode, RSyn public ArgumentsSignature getSyntaxSignature() { return ArgumentsSignature.empty(3); } + + /** + * Tests if the provided node is a loop-body node (also considering wrappers). + */ + public static boolean isLoopBody(Node n) { + Node parent = n.getParent(); + if (parent instanceof WrapperNode) { + Node grandparent = parent.getParent(); + return grandparent instanceof ForRepeatingNode && ((ForRepeatingNode) grandparent).body == parent; + } + return parent instanceof ForRepeatingNode && ((ForRepeatingNode) parent).body == n; + } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 3ab87815debd8fab265f490b00b710d2c0efc683..5897e35a443b428f92f7a5647ba5f94de62f8d09 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -143320,6 +143320,88 @@ debug at #4: `123t` exiting from: f(5) [1] 6 +##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testLoop# +#fun <- function(x) { for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>> +debugging in: fun(3) +debug at #1: { + for (i in seq(x)) cat(i) + cat(5) +} +debug at #1: for (i in seq(x)) cat(i) +debug at #1: cat(i) +1debug at #1: cat(i) +2debug at #1: cat(i) +3debug at #1: cat(5) +5exiting from: fun(3) + +##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testLoop# +#fun <- function(x) { for(i in seq(x)) { cat(i) }; cat(5) }; debug(fun); fun(3)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>> +debugging in: fun(3) +debug at #1: { + for (i in seq(x)) { + cat(i) + } + cat(5) +} +debug at #1: for (i in seq(x)) { + cat(i) +} +debug at #1: cat(i) +1debug at #1: cat(i) +2debug at #1: cat(i) +3debug at #1: cat(5) +5exiting from: fun(3) + +##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testLoop# +#fun <- function(x) { for(i in seq(x)) { cat(i) }; cat(5) }; debug(fun); fun(3)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>>f<<<NEWLINE>>><<<NEWLINE>>> +debugging in: fun(3) +debug at #1: { + for (i in seq(x)) { + cat(i) + } + cat(5) +} +debug at #1: for (i in seq(x)) { + cat(i) +} +debug at #1: cat(i) +1debug at #1: cat(i) +23debug at #1: cat(5) +5exiting from: fun(3) + +##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testLoop# +#fun <- function(x) { for(j in seq(2)) for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>> +debugging in: fun(3) +debug at #1: { + for (j in seq(2)) for (i in seq(x)) cat(i) + cat(5) +} +debug at #1: for (j in seq(2)) for (i in seq(x)) cat(i) +debug at #1: for (i in seq(x)) cat(i) +debug at #1: cat(i) +1debug at #1: cat(i) +2debug at #1: cat(i) +3debug at #1: for (i in seq(x)) cat(i) +debug at #1: cat(i) +1debug at #1: cat(i) +2debug at #1: cat(i) +3debug at #1: cat(5) +5exiting from: fun(3) + +##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testLoop# +#fun <- function(x) { for(j in seq(2)) for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>>f<<<NEWLINE>>>f<<<NEWLINE>>><<<NEWLINE>>> +debugging in: fun(3) +debug at #1: { + for (j in seq(2)) for (i in seq(x)) cat(i) + cat(5) +} +debug at #1: for (j in seq(2)) for (i in seq(x)) cat(i) +debug at #1: for (i in seq(x)) cat(i) +debug at #1: cat(i) +123debug at #1: for (i in seq(x)) cat(i) +123debug at #1: cat(5) +5exiting from: fun(3) + ##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testNoBracket# #f <- function(x) print(x)<<<NEWLINE>>>debug(f)<<<NEWLINE>>>f(5)<<<NEWLINE>>>x<<<NEWLINE>>>n<<<NEWLINE>>> debugging in: f(5) diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java index 7d32146ecb76c6ce69082ef78ed32e6e1b54ff2c..31e9eb103ef2eafc27b18692ee7323abcaba7611 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -41,4 +41,13 @@ public class TestInteractiveDebug extends TestBase { public void testNoBracket() { assertEval("f <- function(x) print(x)\ndebug(f)\nf(5)\nx\nn\n"); } + + @Test + public void testLoop() { + assertEval("fun <- function(x) { for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)\n\n\n\n\n\n\n"); + assertEval("fun <- function(x) { for(i in seq(x)) { cat(i) }; cat(5) }; debug(fun); fun(3)\n\n\n\n\n\n\n"); + assertEval("fun <- function(x) { for(i in seq(x)) { cat(i) }; cat(5) }; debug(fun); fun(3)\n\n\n\nf\n\n"); + assertEval("fun <- function(x) { for(j in seq(2)) for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)\n\n\n\n\n\n\n\n\n\n\n\n"); + assertEval("fun <- function(x) { for(j in seq(2)) for(i in seq(x)) cat(i); cat(5) }; debug(fun); fun(3)\n\n\n\nf\nf\n\n"); + } }