From 05558c580cd83c98d3917b6e818474362c134428 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Mon, 18 Nov 2019 15:01:59 +0100
Subject: [PATCH 01/10] Making sure T-Trace exceptions are treated as regular
 language exceptions

---
 tools/docs/T-Trace-Manual.md                  | 46 +++++++++++++++
 .../agentscript/test/AgentObjectFactory.java  |  8 ++-
 .../agentscript/test/AgentObjectTest.java     | 56 +++++++++++++++++++
 .../agentscript/test/InstrumentNode.java      | 42 ++++++++++++++
 .../api/instrumentation/ProbeNode.java        |  3 +-
 .../oracle/truffle/polyglot/PolyglotImpl.java |  3 +
 6 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java

diff --git a/tools/docs/T-Trace-Manual.md b/tools/docs/T-Trace-Manual.md
index 4dd863a8c2c9..d868cfe1c5ba 100644
--- a/tools/docs/T-Trace-Manual.md
+++ b/tools/docs/T-Trace-Manual.md
@@ -459,6 +459,52 @@ $ node --experimental-options --js.print --agentscript=agent-require.js yourScri
 This initialization sequence is known to work on GraalVM's node `v12.10.0`
 launched with a main `yourScript.js` parameter.
 
+### Handling Exceptions
+
+The `agentscript` code can throw exceptions and they are propagate to the 
+surrounding scripts. Imagine you have a program `seq.js` logging various messages:
+
+```js
+function log(msg) {
+    print(msg);
+}
+
+log('Hello T-Trace!');
+log('How');
+log('are');
+log('You?');
+```
+
+You can register an instrument `term.js` and terminate the execution in the middle of 
+logging:
+
+```js
+agent.on('enter', (ev, frame) => { 
+    if (frame.msg === 'are') {
+        throw "great you are!";
+    }
+}, {
+    roots: true,
+    rootNameFilter: (n) => n === 'log'
+});
+```
+
+The instruments waits for `log('are')` and at that moment it breaks the execution.
+As a result one gets:
+
+```bash
+$ js --polyglot --experimental-options --agentscript=term.js seq.js
+Hello T-Trace!
+How
+great you are!
+        at <js> :=>(<eval>:3:75-97)
+        at <js> log(seq.js:1-3:18-36)
+        at <js> :program(seq.js:7:74-83)
+```
+
+The locations may indeed be slightly different, but otherwise exceptions 
+from T-Trace instruments are treated as regular language exceptions.
+
 <!--
 
 ### TODO:
diff --git a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectFactory.java b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectFactory.java
index 611225e23ac1..4ebfd0ab6ce2 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectFactory.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectFactory.java
@@ -37,6 +37,7 @@
 import org.graalvm.polyglot.Value;
 import static org.junit.Assert.assertNotNull;
 import com.oracle.truffle.tools.agentscript.AgentScript;
+import java.io.ByteArrayOutputStream;
 import java.util.function.Predicate;
 import org.graalvm.polyglot.Engine;
 import org.graalvm.polyglot.HostAccess;
@@ -55,7 +56,12 @@ static AgentScriptAPI.OnConfig createConfig(boolean expressions, boolean stateme
     }
 
     static Context newContext() {
-        return Context.newBuilder().allowExperimentalOptions(true).allowHostAccess(HostAccess.ALL).build();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        return newContext(os, os);
+    }
+
+    static Context newContext(ByteArrayOutputStream out, ByteArrayOutputStream err) {
+        return Context.newBuilder().out(out).err(err).allowExperimentalOptions(true).allowHostAccess(HostAccess.ALL).build();
     }
 
     @Override
diff --git a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
index 1fa0f1df3f92..a1bcb4bee5f4 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
@@ -24,10 +24,13 @@
  */
 package com.oracle.truffle.tools.agentscript.test;
 
+import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.instrumentation.test.InstrumentationTestLanguage;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.test.polyglot.ProxyLanguage;
 import com.oracle.truffle.tools.agentscript.AgentScript;
 import static com.oracle.truffle.tools.agentscript.test.AgentObjectFactory.createConfig;
+import java.io.ByteArrayOutputStream;
 import java.net.URI;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -35,6 +38,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import org.graalvm.polyglot.Context;
+import org.graalvm.polyglot.PolyglotException;
 import org.graalvm.polyglot.Source;
 import org.graalvm.polyglot.Value;
 import org.junit.Assert;
@@ -43,6 +47,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import org.junit.Test;
 
 public class AgentObjectTest {
@@ -280,6 +285,57 @@ public void onExpressionCallback() throws Exception {
         }
     }
 
+    @Test
+    public void onError() throws Exception {
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        try (Context c = AgentObjectFactory.newContext(os, os)) {
+            Value agent = AgentObjectFactory.createAgentObject(c);
+            AgentScriptAPI agentAPI = agent.as(AgentScriptAPI.class);
+            Assert.assertNotNull("Agent API obtained", agentAPI);
+
+            class TE extends RuntimeException implements TruffleException {
+                static final long serialVersionUID = 1L;
+
+                @Override
+                public String getMessage() {
+                    return "TE";
+                }
+
+                @Override
+                public Node getLocation() {
+                    return new InstrumentNode();
+                }
+            }
+
+            agentAPI.on("enter", (ev, frame) -> {
+                throw new TE();
+            }, AgentObjectFactory.createConfig(true, false, false, null));
+
+            // @formatter:off
+            Source sampleScript = Source.newBuilder(InstrumentationTestLanguage.ID,
+                "ROOT(\n" +
+                "  DEFINE(foo,\n" +
+                "    LOOP(10, STATEMENT(EXPRESSION,EXPRESSION))\n" +
+                "  ),\n" +
+                "  CALL(foo)\n" +
+                ")",
+                "sample.px"
+            ).build();
+            // @formatter:on
+
+            try {
+                c.eval(sampleScript);
+                fail("Instrument throws an exception");
+            } catch (PolyglotException ex) {
+                assertEquals("TE", ex.getMessage());
+                assertEquals("INSTR", ex.getSourceLocation().getCharacters().toString());
+            }
+            if (os.toByteArray().length > 0) {
+                fail("Unexpected output: " + os.toString());
+            }
+        }
+    }
+
     @Test
     public void onEnterAndReturn() throws Exception {
         try (Context c = AgentObjectFactory.newContext()) {
diff --git a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java
new file mode 100644
index 000000000000..70d72c2ac31d
--- /dev/null
+++ b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.tools.agentscript.test;
+
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
+
+final class InstrumentNode extends Node {
+
+    InstrumentNode() {
+    }
+
+    @Override
+    public SourceSection getSourceSection() {
+        Source inst = Source.newBuilder("px", "INSTR", "px.inst").build();
+        return inst.createSection(0, inst.getLength());
+    }
+
+}
diff --git a/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/ProbeNode.java b/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/ProbeNode.java
index c2936b4a095d..cef491c207ae 100644
--- a/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/ProbeNode.java
+++ b/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/ProbeNode.java
@@ -53,6 +53,7 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
@@ -906,7 +907,7 @@ final void onEnter(EventContext context, VirtualFrame frame) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     setSeenException();
                 }
-                if (binding.isLanguageBinding()) {
+                if (binding.isLanguageBinding() || t instanceof TruffleException) {
                     throw t;
                 } else {
                     CompilerDirectives.transferToInterpreter();
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
index 351586ce469a..14787a5ede7c 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
@@ -67,6 +67,7 @@
 import org.graalvm.polyglot.proxy.Proxy;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.TruffleOptions;
 import com.oracle.truffle.api.impl.DispatchOutputStream;
 import com.oracle.truffle.api.interop.InteropException;
@@ -361,6 +362,8 @@ static <T extends Throwable> RuntimeException wrapHostException(PolyglotContextI
             return (HostException) e;
         } else if (e instanceof InteropException) {
             throw ((InteropException) e).raise();
+        } else if ((e instanceof RuntimeException) && (e instanceof TruffleException)) {
+            throw (RuntimeException) e;
         }
         try {
             return new HostException(e);

From c83b748ba53cfa80804abd8f1567c6c224a1c397 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Tue, 19 Nov 2019 06:48:07 +0100
Subject: [PATCH 02/10] Showing the expected stacktrace in the documentation

---
 tools/docs/T-Trace-Manual.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/docs/T-Trace-Manual.md b/tools/docs/T-Trace-Manual.md
index a480f048c626..f3f7ee368803 100644
--- a/tools/docs/T-Trace-Manual.md
+++ b/tools/docs/T-Trace-Manual.md
@@ -497,7 +497,7 @@ $ js --polyglot --experimental-options --agentscript=term.js seq.js
 Hello T-Trace!
 How
 great you are!
-        at <js> :=>(<eval>:3:75-97)
+        at <js> :=>(term.js:3:75-97)
         at <js> log(seq.js:1-3:18-36)
         at <js> :program(seq.js:7:74-83)
 ```

From d706ae666ebfddad981d79fe16f2071fd4229b32 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Tue, 19 Nov 2019 06:53:07 +0100
Subject: [PATCH 03/10] Removing special treatment of host exception as
 TruffleException

---
 .../agentscript/test/AgentObjectTest.java     | 56 -------------------
 .../agentscript/test/InstrumentNode.java      | 42 --------------
 .../oracle/truffle/polyglot/PolyglotImpl.java |  3 -
 3 files changed, 101 deletions(-)
 delete mode 100644 tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java

diff --git a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
index a1bcb4bee5f4..1fa0f1df3f92 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/AgentObjectTest.java
@@ -24,13 +24,10 @@
  */
 package com.oracle.truffle.tools.agentscript.test;
 
-import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.instrumentation.test.InstrumentationTestLanguage;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.test.polyglot.ProxyLanguage;
 import com.oracle.truffle.tools.agentscript.AgentScript;
 import static com.oracle.truffle.tools.agentscript.test.AgentObjectFactory.createConfig;
-import java.io.ByteArrayOutputStream;
 import java.net.URI;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -38,7 +35,6 @@
 import java.util.Set;
 import java.util.TreeSet;
 import org.graalvm.polyglot.Context;
-import org.graalvm.polyglot.PolyglotException;
 import org.graalvm.polyglot.Source;
 import org.graalvm.polyglot.Value;
 import org.junit.Assert;
@@ -47,7 +43,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import org.junit.Test;
 
 public class AgentObjectTest {
@@ -285,57 +280,6 @@ public void onExpressionCallback() throws Exception {
         }
     }
 
-    @Test
-    public void onError() throws Exception {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        try (Context c = AgentObjectFactory.newContext(os, os)) {
-            Value agent = AgentObjectFactory.createAgentObject(c);
-            AgentScriptAPI agentAPI = agent.as(AgentScriptAPI.class);
-            Assert.assertNotNull("Agent API obtained", agentAPI);
-
-            class TE extends RuntimeException implements TruffleException {
-                static final long serialVersionUID = 1L;
-
-                @Override
-                public String getMessage() {
-                    return "TE";
-                }
-
-                @Override
-                public Node getLocation() {
-                    return new InstrumentNode();
-                }
-            }
-
-            agentAPI.on("enter", (ev, frame) -> {
-                throw new TE();
-            }, AgentObjectFactory.createConfig(true, false, false, null));
-
-            // @formatter:off
-            Source sampleScript = Source.newBuilder(InstrumentationTestLanguage.ID,
-                "ROOT(\n" +
-                "  DEFINE(foo,\n" +
-                "    LOOP(10, STATEMENT(EXPRESSION,EXPRESSION))\n" +
-                "  ),\n" +
-                "  CALL(foo)\n" +
-                ")",
-                "sample.px"
-            ).build();
-            // @formatter:on
-
-            try {
-                c.eval(sampleScript);
-                fail("Instrument throws an exception");
-            } catch (PolyglotException ex) {
-                assertEquals("TE", ex.getMessage());
-                assertEquals("INSTR", ex.getSourceLocation().getCharacters().toString());
-            }
-            if (os.toByteArray().length > 0) {
-                fail("Unexpected output: " + os.toString());
-            }
-        }
-    }
-
     @Test
     public void onEnterAndReturn() throws Exception {
         try (Context c = AgentObjectFactory.newContext()) {
diff --git a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java b/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java
deleted file mode 100644
index 70d72c2ac31d..000000000000
--- a/tools/src/com.oracle.truffle.tools.agentscript.test/src/com/oracle/truffle/tools/agentscript/test/InstrumentNode.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2019, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.agentscript.test;
-
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.source.Source;
-import com.oracle.truffle.api.source.SourceSection;
-
-final class InstrumentNode extends Node {
-
-    InstrumentNode() {
-    }
-
-    @Override
-    public SourceSection getSourceSection() {
-        Source inst = Source.newBuilder("px", "INSTR", "px.inst").build();
-        return inst.createSection(0, inst.getLength());
-    }
-
-}
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
index 14787a5ede7c..351586ce469a 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
@@ -67,7 +67,6 @@
 import org.graalvm.polyglot.proxy.Proxy;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.TruffleOptions;
 import com.oracle.truffle.api.impl.DispatchOutputStream;
 import com.oracle.truffle.api.interop.InteropException;
@@ -362,8 +361,6 @@ static <T extends Throwable> RuntimeException wrapHostException(PolyglotContextI
             return (HostException) e;
         } else if (e instanceof InteropException) {
             throw ((InteropException) e).raise();
-        } else if ((e instanceof RuntimeException) && (e instanceof TruffleException)) {
-            throw (RuntimeException) e;
         }
         try {
             return new HostException(e);

From ba1ea588a875211921bf6166b238de45f3df84a0 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Tue, 19 Nov 2019 07:13:58 +0100
Subject: [PATCH 04/10] Testing behavior of JavaScript agent throwing an
 exception

---
 vm/tests/all/agentscript/agent-exception.js   |  8 ++++++++
 vm/tests/all/agentscript/agent-exception.test | 14 ++++++++++++++
 vm/tests/all/agentscript/log.js               |  8 ++++++++
 3 files changed, 30 insertions(+)
 create mode 100644 vm/tests/all/agentscript/agent-exception.js
 create mode 100644 vm/tests/all/agentscript/agent-exception.test
 create mode 100644 vm/tests/all/agentscript/log.js

diff --git a/vm/tests/all/agentscript/agent-exception.js b/vm/tests/all/agentscript/agent-exception.js
new file mode 100644
index 000000000000..76579eaacfdf
--- /dev/null
+++ b/vm/tests/all/agentscript/agent-exception.js
@@ -0,0 +1,8 @@
+agent.on('enter', function checkLogging(ev, frame) {
+    if (frame.msg === 'are') {
+        throw "great you are!";
+    }
+}, {
+    roots: true,
+    rootNameFilter: (n) => n === 'log'
+});
diff --git a/vm/tests/all/agentscript/agent-exception.test b/vm/tests/all/agentscript/agent-exception.test
new file mode 100644
index 000000000000..2f9b6d706e38
--- /dev/null
+++ b/vm/tests/all/agentscript/agent-exception.test
@@ -0,0 +1,14 @@
+>[7] js --jvm --experimental-options --agentscript=agent-exception.js log.js
+Hello T-Trace.
+How
+great you are!
+.*at <js> checkLogging.*
+.*at <js> log.log.js:1-3:18-36.
+.*at <js> :program.log.js:7:74-83.
+>[7] js --experimental-options --agentscript=agent-exception.js log.js
+Hello T-Trace.
+How
+great you are!
+.*at <js> checkLogging.*
+.*at <js> log.log.js:1-3:18-36.
+.*at <js> :program.log.js:7:74-83.
diff --git a/vm/tests/all/agentscript/log.js b/vm/tests/all/agentscript/log.js
new file mode 100644
index 000000000000..22fa2b1c3e99
--- /dev/null
+++ b/vm/tests/all/agentscript/log.js
@@ -0,0 +1,8 @@
+function log(msg) {
+    print(msg);
+}
+
+log('Hello T-Trace!');
+log('How');
+log('are');
+log('You?');

From e3b15da01bd937002783ca87f4ebf8612dcd65fb Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Thu, 5 Dec 2019 09:54:26 +0100
Subject: [PATCH 05/10] Using EventContext.createError to propagate the
 exception to the language

---
 .../agentscript/impl/AgentExecutionNode.java  | 15 ++++-----
 .../agentscript/impl/EventContextObject.java  |  8 +++++
 vm/tests/all/agentscript/agent-exception.js   | 11 +++++++
 vm/tests/all/agentscript/agent-exception.test | 31 +++++++++++++++----
 vm/tests/all/agentscript/log.js               | 29 ++++++++++++++---
 5 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
index 681b1ec46833..af97aa81b5b5 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
@@ -24,6 +24,7 @@
  */
 package com.oracle.truffle.tools.agentscript.impl;
 
+import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrumentation.EventContext;
 import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
@@ -59,8 +60,8 @@ protected void onEnter(VirtualFrame frame) {
         if (enter != null) {
             try {
                 enterDispatch.execute(enter, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException ex) {
-                throw AgentException.raise(ex);
+            } catch (InteropException | RuntimeException ex) {
+                throw ctx.rethrow(ex);
             }
         }
     }
@@ -70,8 +71,8 @@ protected void onReturnValue(VirtualFrame frame, Object result) {
         if (exit != null) {
             try {
                 exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException ex) {
-                throw AgentException.raise(ex);
+            } catch (InteropException | RuntimeException ex) {
+                throw ctx.rethrow(ex);
             }
         }
     }
@@ -80,9 +81,9 @@ protected void onReturnValue(VirtualFrame frame, Object result) {
     protected void onReturnExceptional(VirtualFrame frame, Throwable exception) {
         if (exit != null) {
             try {
-                enterDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException ex) {
-                throw AgentException.raise(ex);
+                exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
+            } catch (InteropException | RuntimeException ex) {
+                throw ctx.rethrow(ex);
             }
         }
     }
diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
index 7cce7b466d2b..1a936302e0a7 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
@@ -25,6 +25,7 @@
 package com.oracle.truffle.tools.agentscript.impl;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.instrumentation.EventContext;
 import com.oracle.truffle.api.interop.InteropLibrary;
 import com.oracle.truffle.api.interop.TruffleObject;
@@ -42,6 +43,13 @@ final class EventContextObject implements TruffleObject {
         this.context = context;
     }
 
+    RuntimeException rethrow(Exception ex) {
+        if (ex instanceof TruffleException && ex instanceof RuntimeException) {
+            return context.createError((RuntimeException) ex);
+        }
+        throw AgentException.raise(ex);
+    }
+
     @ExportMessage
     static boolean hasMembers(EventContextObject obj) {
         return true;
diff --git a/vm/tests/all/agentscript/agent-exception.js b/vm/tests/all/agentscript/agent-exception.js
index 76579eaacfdf..a5337f3b2c57 100644
--- a/vm/tests/all/agentscript/agent-exception.js
+++ b/vm/tests/all/agentscript/agent-exception.js
@@ -6,3 +6,14 @@ agent.on('enter', function checkLogging(ev, frame) {
     roots: true,
     rootNameFilter: (n) => n === 'log'
 });
+agent.on('return', function checkLogging(ev, frame) {
+    if (frame.msg === 'do') {
+        throw "you feel?";
+    }
+    if (frame.msg === 'bad') {
+        throw "good you are?";
+    }
+}, {
+    roots: true,
+    rootNameFilter: (n) => n === 'log'
+});
diff --git a/vm/tests/all/agentscript/agent-exception.test b/vm/tests/all/agentscript/agent-exception.test
index 2f9b6d706e38..f2c22802bda1 100644
--- a/vm/tests/all/agentscript/agent-exception.test
+++ b/vm/tests/all/agentscript/agent-exception.test
@@ -1,14 +1,33 @@
->[7] js --jvm --experimental-options --agentscript=agent-exception.js log.js
+>[7] js --jvm --experimental-options --agentscript=agent-exception.js -f log.js -e "howAreYou()"
 Hello T-Trace.
 How
 great you are!
 .*at <js> checkLogging.*
-.*at <js> log.log.js:1-3:18-36.
-.*at <js> :program.log.js:7:74-83.
->[7] js --experimental-options --agentscript=agent-exception.js log.js
+.*at <js> log.log.js:1-6:18-103.
+.*at <js> howAreYou.log.js:11:176-185.
+
+>[7] js --experimental-options --agentscript=agent-exception.js -f log.js -e "howAreYou()"
 Hello T-Trace.
 How
 great you are!
 .*at <js> checkLogging.*
-.*at <js> log.log.js:1-3:18-36.
-.*at <js> :program.log.js:7:74-83.
+.*at <js> log.log.js:1-6:18-103.
+.*at <js> howAreYou.log.js:11:176-185.
+
+>[7] js --experimental-options --agentscript=agent-exception.js -f log.js -e "howDoYouDo()"
+Hello T-Trace!
+How
+do
+you feel?
+.*at <js> checkLogging.*
+.*at <js> log.log.js:1-6:18-103.
+.*at <js> howDoYouDo.log.js:18:279-287.
+.*at <js> :program.<eval_script>:1:0-11.
+>[7] js --experimental-options --agentscript=agent-exception.js -f log.js -e "areYouBad()"
+Hello T-Trace!
+How
+good you are?
+.*at <js> checkLogging.*
+.*at <js> log.log.js:1-6:18-103.
+.*at <js> areYouBad.log.js:26:395-404.
+.*at <js> :program.<eval_script>:1:0-10.
diff --git a/vm/tests/all/agentscript/log.js b/vm/tests/all/agentscript/log.js
index 22fa2b1c3e99..14b79b7ff3af 100644
--- a/vm/tests/all/agentscript/log.js
+++ b/vm/tests/all/agentscript/log.js
@@ -1,8 +1,29 @@
 function log(msg) {
+    if (msg === 'bad') {
+        throw 'bad is not allowed';
+    }
     print(msg);
 }
 
-log('Hello T-Trace!');
-log('How');
-log('are');
-log('You?');
+function howAreYou() {
+    log('Hello T-Trace!');
+    log('How');
+    log('are');
+    log('You?');
+}
+
+function howDoYouDo() {
+    log('Hello T-Trace!');
+    log('How');
+    log('do');
+    log('you');
+    log('do?');
+}
+
+function areYouBad() {
+    log('Hello T-Trace!');
+    log('How');
+    log('bad');
+    log('are');
+    log('you?');
+}

From 76cd0b04e5d372dc4dd9252627357da407ef268f Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Fri, 6 Dec 2019 08:31:30 +0100
Subject: [PATCH 06/10] Rephrasing the prose section about handling exceptions

---
 tools/docs/T-Trace-Manual.md | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/tools/docs/T-Trace-Manual.md b/tools/docs/T-Trace-Manual.md
index f3f7ee368803..cfa71a29c2d1 100644
--- a/tools/docs/T-Trace-Manual.md
+++ b/tools/docs/T-Trace-Manual.md
@@ -461,8 +461,9 @@ launched with a main `yourScript.js` parameter.
 
 ### Handling Exceptions
 
-The `agentscript` code can throw exceptions and they are propagate to the 
-surrounding scripts. Imagine you have a program `seq.js` logging various messages:
+The T-Trace agents can throw exceptions which are then propagated to the
+surrounding user scripts. Imagine you have a program `seq.js`
+logging various messages:
 
 ```js
 function log(msg) {
@@ -475,13 +476,13 @@ log('are');
 log('You?');
 ```
 
-You can register an instrument `term.js` and terminate the execution in the middle of 
-logging:
+You can register an instrument `term.js` and terminate the execution in the middle
+of the `seq.js` program execution based on observing the logged message:
 
 ```js
 agent.on('enter', (ev, frame) => { 
     if (frame.msg === 'are') {
-        throw "great you are!";
+        throw 'great you are!';
     }
 }, {
     roots: true,
@@ -489,8 +490,9 @@ agent.on('enter', (ev, frame) => {
 });
 ```
 
-The instruments waits for `log('are')` and at that moment it breaks the execution.
-As a result one gets:
+The `term.js` instrument waits for a call to `log` function with message 'are'
+and at that moment it emits its own exception effectively interrupting the user
+program execution. As a result one gets:
 
 ```bash
 $ js --polyglot --experimental-options --agentscript=term.js seq.js
@@ -502,8 +504,10 @@ great you are!
         at <js> :program(seq.js:7:74-83)
 ```
 
-The locations may indeed be slightly different, but otherwise exceptions 
-from T-Trace instruments are treated as regular language exceptions.
+The exceptions emitted by T-Trace instruments are treated as regular language
+exceptions. The `seq.js` program could use regular `try { ... } catch (e) { ... }`
+block to catch them and deal with them as if they were emitted by the regular
+user code.
 
 <!--
 

From 4e0e73c91f72620e81c869054b9e768eda45fb5b Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Fri, 6 Dec 2019 08:31:46 +0100
Subject: [PATCH 07/10] Removing unused import

---
 .../truffle/tools/agentscript/impl/AgentExecutionNode.java       | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
index af97aa81b5b5..ff421660520d 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
@@ -24,7 +24,6 @@
  */
 package com.oracle.truffle.tools.agentscript.impl;
 
-import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrumentation.EventContext;
 import com.oracle.truffle.api.instrumentation.ExecutionEventNode;

From d90cec223379f60e5fa3eaeb3caf12a4d5ebe448 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Fri, 13 Dec 2019 06:56:25 +0100
Subject: [PATCH 08/10] Handling Interop and Runtime exceptions in a different
 way

---
 .../tools/agentscript/impl/AgentExecutionNode.java  | 12 +++++++++---
 .../tools/agentscript/impl/EventContextObject.java  | 13 ++++++++++---
 vm/tests/all/agentscript/interop-exception.rb       |  5 +++++
 vm/tests/all/agentscript/interop-exception.test     |  3 +++
 4 files changed, 27 insertions(+), 6 deletions(-)
 create mode 100644 vm/tests/all/agentscript/interop-exception.rb
 create mode 100644 vm/tests/all/agentscript/interop-exception.test

diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
index ff421660520d..edb0e6ad7d85 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/AgentExecutionNode.java
@@ -59,7 +59,9 @@ protected void onEnter(VirtualFrame frame) {
         if (enter != null) {
             try {
                 enterDispatch.execute(enter, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException | RuntimeException ex) {
+            } catch (InteropException ex) {
+                throw ctx.wrap(enter, 2, ex);
+            } catch (RuntimeException ex) {
                 throw ctx.rethrow(ex);
             }
         }
@@ -70,7 +72,9 @@ protected void onReturnValue(VirtualFrame frame, Object result) {
         if (exit != null) {
             try {
                 exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException | RuntimeException ex) {
+            } catch (InteropException ex) {
+                throw ctx.wrap(exit, 2, ex);
+            } catch (RuntimeException ex) {
                 throw ctx.rethrow(ex);
             }
         }
@@ -81,7 +85,9 @@ protected void onReturnExceptional(VirtualFrame frame, Throwable exception) {
         if (exit != null) {
             try {
                 exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
-            } catch (InteropException | RuntimeException ex) {
+            } catch (InteropException ex) {
+                throw ctx.wrap(exit, 2, ex);
+            } catch (RuntimeException ex) {
                 throw ctx.rethrow(ex);
             }
         }
diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
index 1a936302e0a7..9ee23c0ffbff 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
@@ -27,6 +27,7 @@
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.TruffleException;
 import com.oracle.truffle.api.instrumentation.EventContext;
+import com.oracle.truffle.api.interop.InteropException;
 import com.oracle.truffle.api.interop.InteropLibrary;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.UnknownIdentifierException;
@@ -43,9 +44,15 @@ final class EventContextObject implements TruffleObject {
         this.context = context;
     }
 
-    RuntimeException rethrow(Exception ex) {
-        if (ex instanceof TruffleException && ex instanceof RuntimeException) {
-            return context.createError((RuntimeException) ex);
+    RuntimeException wrap(Object target, int arity, InteropException ex) {
+        IllegalStateException ill = new IllegalStateException("Cannot invoke " + target + " with " + arity + " arguments: " + ex.getMessage());
+        ill.initCause(ex);
+        return context.createError(ill);
+    }
+
+    RuntimeException rethrow(RuntimeException ex) {
+        if (ex instanceof TruffleException) {
+            return context.createError(ex);
         }
         throw AgentException.raise(ex);
     }
diff --git a/vm/tests/all/agentscript/interop-exception.rb b/vm/tests/all/agentscript/interop-exception.rb
new file mode 100644
index 000000000000..0f097bc6ca3a
--- /dev/null
+++ b/vm/tests/all/agentscript/interop-exception.rb
@@ -0,0 +1,5 @@
+agent.on("enter", ->(a1) {
+  puts "What's #{a1}?"
+}, {
+  statements: true
+});
diff --git a/vm/tests/all/agentscript/interop-exception.test b/vm/tests/all/agentscript/interop-exception.test
new file mode 100644
index 000000000000..f9c9b3c6757f
--- /dev/null
+++ b/vm/tests/all/agentscript/interop-exception.test
@@ -0,0 +1,3 @@
+>[1] ruby --experimental-options --agentscript=interop-exception.rb -e 'def x(t) puts("x=#{t}"); end; x(6 * 7)'
+interop-exception.rb:1.*wrong number of arguments.*given 2.*expected 1.*
+from.*main.*

From 9b3713b6a0ffa6fc0b4174683432cc6f3a25a18d Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Fri, 13 Dec 2019 11:23:22 +0100
Subject: [PATCH 09/10] There can be some prefix before "from"

---
 vm/tests/all/agentscript/interop-exception.test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vm/tests/all/agentscript/interop-exception.test b/vm/tests/all/agentscript/interop-exception.test
index f9c9b3c6757f..005f80bc79bc 100644
--- a/vm/tests/all/agentscript/interop-exception.test
+++ b/vm/tests/all/agentscript/interop-exception.test
@@ -1,3 +1,3 @@
 >[1] ruby --experimental-options --agentscript=interop-exception.rb -e 'def x(t) puts("x=#{t}"); end; x(6 * 7)'
 interop-exception.rb:1.*wrong number of arguments.*given 2.*expected 1.*
-from.*main.*
+.*from.*main.*

From 37832476b42a5d07d52c1facd8ad6b3e55f9fa11 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Fri, 13 Dec 2019 11:39:41 +0100
Subject: [PATCH 10/10] Propagating only non-internal errors

---
 .../truffle/tools/agentscript/impl/EventContextObject.java  | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
index 9ee23c0ffbff..6913bba4a21b 100644
--- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
+++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/EventContextObject.java
@@ -52,9 +52,11 @@ RuntimeException wrap(Object target, int arity, InteropException ex) {
 
     RuntimeException rethrow(RuntimeException ex) {
         if (ex instanceof TruffleException) {
-            return context.createError(ex);
+            if (!((TruffleException) ex).isInternalError()) {
+                return context.createError(ex);
+            }
         }
-        throw AgentException.raise(ex);
+        throw ex;
     }
 
     @ExportMessage