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