GraalVM/Polyglot: 如何以编程方式获取 SourceLocation
GraalVM/Polyglot: how to get SourceLocation programmatically
有没有办法从 java 获取当前源位置 (SourceSection)?
例如通过 context.eval() 执行的 js 脚本调用 java 方法,java 方法记录当前 js 脚本名称+行
PolyglotException 有一个提供此信息的 getSourceLocation()。 polyglot 的堆栈跟踪似乎也包含有关源位置的信息,例如在:程序(未命名:2:23-53)
Hacky 解决方案:您可以将 new Error().stack
作为参数传递给 java 函数以获取堆栈跟踪。鉴于
public class A {
public A() {}
public void foo(String x) {
System.out.println("MY ARGUMENT IS: " + x);
}
}
你可以
$GRAALVM_HOME/bin/js --jvm --vm.cp=.
> function bar() { var x = new (Java.type("A"))(); x.foo(new Error().stack) }
> bar()
MY ARGUMENT IS: Error
at bar (<shell>:6:1:56)
at <shell>:7:1:1
我找到了一个解决方案,但我仍然不确定它是好是坏。但目前似乎只有它有效。
基本上,我需要添加一堆 --add-opens 到 java args:
--add-opens org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.frame=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.nodes=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.source=ALL-UNNAMED
然后使用 Truffle 运行时我能够获得调用者框架和 SourceSelection
Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection()
我知道你很久以前就问过这个问题,但我还是第一次看到。
这是一种轻松到达当前位置的方法:
static StackFrame getCurrentLocation() {
PolyglotException e = Context.getCurrent().asValue(new RuntimeException()).as(PolyglotException.class);
for (StackFrame frame: e.getPolyglotStackTrace()) {
if (frame.isGuestFrame()) {
return frame;
}
}
return null;
}
这是一个完整的可运行示例:
public class Test {
public static void main(String[] args) {
try (Context context = Context.newBuilder().allowHostAccess(HostAccess.ALL).build()) {
context.getBindings("js").putMember("test", new Test());
Source source = Source.newBuilder("js", "test.callback()", "mysource.js").buildLiteral();
context.eval(source);
}
}
public void callback() {
System.out.println(getCurrentLocation());
}
static StackFrame getCurrentLocation() {
PolyglotException e = Context.getCurrent().asValue(new RuntimeException()).as(PolyglotException.class);
for (StackFrame frame: e.getPolyglotStackTrace()) {
if (frame.isGuestFrame()) {
return frame;
}
}
return null;
}
}
这会打印:
<js> :program(mysource.js:1:0-14)
有没有办法从 java 获取当前源位置 (SourceSection)?
例如通过 context.eval() 执行的 js 脚本调用 java 方法,java 方法记录当前 js 脚本名称+行
PolyglotException 有一个提供此信息的 getSourceLocation()。 polyglot 的堆栈跟踪似乎也包含有关源位置的信息,例如在:程序(未命名:2:23-53)
Hacky 解决方案:您可以将 new Error().stack
作为参数传递给 java 函数以获取堆栈跟踪。鉴于
public class A {
public A() {}
public void foo(String x) {
System.out.println("MY ARGUMENT IS: " + x);
}
}
你可以
$GRAALVM_HOME/bin/js --jvm --vm.cp=.
> function bar() { var x = new (Java.type("A"))(); x.foo(new Error().stack) }
> bar()
MY ARGUMENT IS: Error
at bar (<shell>:6:1:56)
at <shell>:7:1:1
我找到了一个解决方案,但我仍然不确定它是好是坏。但目前似乎只有它有效。
基本上,我需要添加一堆 --add-opens 到 java args:
--add-opens org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.frame=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.nodes=ALL-UNNAMED
--add-opens org.graalvm.truffle/com.oracle.truffle.api.source=ALL-UNNAMED
然后使用 Truffle 运行时我能够获得调用者框架和 SourceSelection
Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection()
我知道你很久以前就问过这个问题,但我还是第一次看到。
这是一种轻松到达当前位置的方法:
static StackFrame getCurrentLocation() {
PolyglotException e = Context.getCurrent().asValue(new RuntimeException()).as(PolyglotException.class);
for (StackFrame frame: e.getPolyglotStackTrace()) {
if (frame.isGuestFrame()) {
return frame;
}
}
return null;
}
这是一个完整的可运行示例:
public class Test {
public static void main(String[] args) {
try (Context context = Context.newBuilder().allowHostAccess(HostAccess.ALL).build()) {
context.getBindings("js").putMember("test", new Test());
Source source = Source.newBuilder("js", "test.callback()", "mysource.js").buildLiteral();
context.eval(source);
}
}
public void callback() {
System.out.println(getCurrentLocation());
}
static StackFrame getCurrentLocation() {
PolyglotException e = Context.getCurrent().asValue(new RuntimeException()).as(PolyglotException.class);
for (StackFrame frame: e.getPolyglotStackTrace()) {
if (frame.isGuestFrame()) {
return frame;
}
}
return null;
}
}
这会打印:
<js> :program(mysource.js:1:0-14)