Skip to content

Commit

Permalink
[GR-19613] T-Trace exceptions are normal language exceptions.
Browse files Browse the repository at this point in the history
PullRequest: graal/4916
  • Loading branch information
Jaroslav Tulach committed Dec 13, 2019
2 parents 7320bcd + 3783247 commit 0599786
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 5 deletions.
50 changes: 50 additions & 0 deletions tools/docs/T-Trace-Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,56 @@ $ 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 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) {
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 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!';
}
}, {
roots: true,
rootNameFilter: (n) => n === 'log'
});
```

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
Hello T-Trace!
How
great you are!
at <js> :=>(term.js:3:75-97)
at <js> log(seq.js:1-3:18-36)
at <js> :program(seq.js:7:74-83)
```

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.

<!--
### TODO:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ protected void onEnter(VirtualFrame frame) {
try {
enterDispatch.execute(enter, ctx, new VariablesObject(env, this, frame));
} catch (InteropException ex) {
throw AgentException.raise(ex);
throw ctx.wrap(enter, 2, ex);
} catch (RuntimeException ex) {
throw ctx.rethrow(ex);
}
}
}
Expand All @@ -71,7 +73,9 @@ protected void onReturnValue(VirtualFrame frame, Object result) {
try {
exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
} catch (InteropException ex) {
throw AgentException.raise(ex);
throw ctx.wrap(exit, 2, ex);
} catch (RuntimeException ex) {
throw ctx.rethrow(ex);
}
}
}
Expand All @@ -80,9 +84,11 @@ 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));
exitDispatch.execute(exit, ctx, new VariablesObject(env, this, frame));
} catch (InteropException ex) {
throw AgentException.raise(ex);
throw ctx.wrap(exit, 2, ex);
} catch (RuntimeException ex) {
throw ctx.rethrow(ex);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
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.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
Expand All @@ -42,6 +44,21 @@ final class EventContextObject implements TruffleObject {
this.context = context;
}

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) {
if (!((TruffleException) ex).isInternalError()) {
return context.createError(ex);
}
}
throw ex;
}

@ExportMessage
static boolean hasMembers(EventContextObject obj) {
return true;
Expand Down
19 changes: 19 additions & 0 deletions vm/tests/all/agentscript/agent-exception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
agent.on('enter', function checkLogging(ev, frame) {
if (frame.msg === 'are') {
throw "great you are!";
}
}, {
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'
});
33 changes: 33 additions & 0 deletions vm/tests/all/agentscript/agent-exception.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
>[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-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-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.
5 changes: 5 additions & 0 deletions vm/tests/all/agentscript/interop-exception.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
agent.on("enter", ->(a1) {
puts "What's #{a1}?"
}, {
statements: true
});
3 changes: 3 additions & 0 deletions vm/tests/all/agentscript/interop-exception.test
Original file line number Diff line number Diff line change
@@ -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.*
29 changes: 29 additions & 0 deletions vm/tests/all/agentscript/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
function log(msg) {
if (msg === 'bad') {
throw 'bad is not allowed';
}
print(msg);
}

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?');
}

0 comments on commit 0599786

Please sign in to comment.