From 80e19306f230a9a7e318e9a176813fb0e1c0a9ca Mon Sep 17 00:00:00 2001 From: Martin Entlicher <martin.entlicher@oracle.com> Date: Wed, 17 Jan 2018 12:03:38 +0100 Subject: [PATCH] [GR-2011] Update wrapper nodes and add a debugger test of unwind of frames. --- .../function/RCallBaseNodeWrapperFactory.java | 84 +++++++++++++------ .../instrumentation/RNodeWrapperFactory.java | 80 +++++++++++++----- .../truffle/r/test/tck/FastRDebugTest.java | 66 +++++++++++++-- mx.fastr/suite.py | 2 +- 4 files changed, 176 insertions(+), 56 deletions(-) diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNodeWrapperFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNodeWrapperFactory.java index 8bb9c406ad..49f2a6bb05 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNodeWrapperFactory.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNodeWrapperFactory.java @@ -56,41 +56,77 @@ public class RCallBaseNodeWrapperFactory implements InstrumentableFactory<RCallB @Override public Object execute(VirtualFrame frame) { - try { - probeNode.onEnter(frame); - Object returnValue = delegate.execute(frame); - probeNode.onReturnValue(frame, returnValue); - return returnValue; - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.execute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } } + return returnValue; } @Override public Object visibleExecute(VirtualFrame frame) { - try { - probeNode.onEnter(frame); - Object returnValue = delegate.visibleExecute(frame); - probeNode.onReturnValue(frame, returnValue); - return returnValue; - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.visibleExecute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } } + return returnValue; } @Override public Object execute(VirtualFrame frame, Object function) { - try { - probeNode.onEnter(frame); - Object returnValue = delegate.execute(frame, function); - probeNode.onReturnValue(frame, returnValue); - return returnValue; - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.execute(frame, function); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } } + return returnValue; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java index de50cdebb7..e2b2b0e8cb 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java @@ -58,40 +58,74 @@ public final class RNodeWrapperFactory implements InstrumentableFactory<RNode> { @Override public Object execute(VirtualFrame frame) { - try { - probeNode.onEnter(frame); - Object returnValue = delegate.execute(frame); - probeNode.onReturnValue(frame, returnValue); - return returnValue; - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.execute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } } + return returnValue; } @Override public void voidExecute(VirtualFrame frame) { - try { - probeNode.onEnter(frame); - delegate.voidExecute(frame); - probeNode.onReturnValue(frame, null); - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + delegate.voidExecute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, null); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + break; + } + throw t; + } } } @Override public Object visibleExecute(VirtualFrame frame) { - try { - probeNode.onEnter(frame); - Object returnValue = delegate.visibleExecute(frame); - probeNode.onReturnValue(frame, returnValue); - return returnValue; - } catch (Throwable t) { - probeNode.onReturnExceptional(frame, t); - throw t; + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.visibleExecute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } } + return returnValue; } @Override diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java index d28904a26b..94e4f924a4 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java @@ -29,15 +29,18 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import com.oracle.truffle.api.debug.Breakpoint; @@ -56,7 +59,6 @@ import com.oracle.truffle.tck.DebuggerTester; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; -import org.junit.Ignore; public class FastRDebugTest { private Debugger debugger; @@ -386,7 +388,7 @@ public class FastRDebugTest { assertArguments(1, "main(1, 2, 3, 4)"); stepInto(1); - assertArguments(2, "x <- 10L", "a", "b", "c", "d"); + assertArguments(2, "x <- 10L", "a", "1.0", "b", "2.0", "c", "3.0", "d", "4.0"); continueExecution(); performWork(); @@ -496,6 +498,49 @@ public class FastRDebugTest { assertExecutedOK(); } + @Test + @Ignore + public void testReenterArgumentsAndValues() throws Throwable { + // Test that after a re-enter, arguments are kept and variables are cleared. + final Source source = sourceFromText("" + + "main <- function () {\n" + + " i <- 10\n" + + " fnc(i <- i + 1, 20)\n" + + "}\n" + + "fnc <- function(n, m) {\n" + + " x <- n + m\n" + + " n <- m - n\n" + + " m <- m / 2\n" + + " x <- x + n * m\n" + + " x\n" + + "}\n" + + "main()\n", "testReenterArgsAndVals.r"); + + run.addLast(() -> { + assertNull(suspendedEvent); + assertNotNull(debuggerSession); + debuggerSession.install(Breakpoint.newBuilder(DebuggerTester.getSourceImpl(source)).lineIs(6).build()); + }); + + assertArguments(6, "x <- n + m", "n", "<unevaluated>", "m", "20.0"); + assertScope(6, "x <- n + m", false, true, "n", "<unevaluated>", "m", "20.0"); + stepOver(4); + assertArguments(10, "x", "n", "9.0", "m", "10.0"); + assertScope(10, "x", false, true, "n", "9.0", "m", "10.0", "x", "121.0"); + run.addLast(() -> suspendedEvent.prepareUnwindFrame(suspendedEvent.getTopStackFrame())); + assertArguments(3, "return fnc(i <- i + 1, 20)"); + assertScope(3, "return fnc(i <- i + 1, 20)", false, true, "i", "11.0"); + continueExecution(); + assertArguments(6, "x <- n + m", "n", "11.0", "m", "20.0"); + assertScope(6, "x <- n + m", false, true, "n", "11.0", "m", "20.0"); + continueExecution(); + + performWork(); + Value ret = context.eval(source); + assertEquals(121, ret.asInt()); + assertExecutedOK(); + } + private void performWork() { try { if (ex == null && !run.isEmpty()) { @@ -609,19 +654,24 @@ public class FastRDebugTest { scope = suspendedEvent.getSession().getTopScope("R"); } - Set<String> actualIdentifiers = new HashSet<>(); - scope.getArguments().forEach((x) -> actualIdentifiers.add(x.getName())); + int n = expectedArgs.length / 2; + List<DebugValue> actualValues = new ArrayList<>(n); + scope.getArguments().forEach((x) -> actualValues.add(x)); - assertEquals(line + ": " + code, expectedArgs.length, actualIdentifiers.size()); + assertEquals(line + ": " + code, n, actualValues.size()); - Set<String> expectedIds = new HashSet<>(Arrays.asList(expectedArgs)); - Assert.assertEquals(expectedIds, actualIdentifiers); + for (int i = 0; i < n; i++) { + int i2 = i << 1; + assertEquals(expectedArgs[i2], actualValues.get(i).getName()); + assertEquals(expectedArgs[i2 + 1], actualValues.get(i).as(String.class)); + } if (!run.isEmpty()) { run.removeFirst().run(); } } catch (RuntimeException | Error e) { + e.printStackTrace(System.err); final DebugStackFrame frame = suspendedEvent.getTopStackFrame(); frame.forEach(var -> { System.out.println(var); @@ -700,7 +750,7 @@ public class FastRDebugTest { /** * Assert either meta object or string value for a set of variables. - * + * * @param expectedSource expected source in which the values should be examined. * @param metaObjects <code>true</code> for checking metaObject or <code>false</code> for * checking <code>value.as(String.class)</code>. diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py index e7e0e1e4d4..04046f4e52 100644 --- a/mx.fastr/suite.py +++ b/mx.fastr/suite.py @@ -7,7 +7,7 @@ suite = { { "name" : "truffle", "subdir" : True, - "version" : "e140680ae7ebc4329e5cd96889258a75b6987dfe", + "version" : "3a00d021027f4136667915386f83b56311db7c12", "urls" : [ {"url" : "https://github.com/graalvm/graal", "kind" : "git"}, {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, -- GitLab