0

有没有办法从java获取当前源位置(SourceSection)?

例如通过 context.eval() 执行的 js 脚本调用 java 方法,java 方法记录当前 js 脚本名称+行

PolyglotException 有一个提供此信息的 getSourceLocation()。来自 polyglot 的堆栈跟踪似乎包含有关源位置的信息,例如:program(Unnamed:2:23-53)

4

3 回答 3

1

我知道你很久以前就问过这个问题,但我只是第一次看到它。

这是一种轻松到达当前位置的方法:

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)
于 2021-08-24T19:39:46.367 回答
0

哈克解决方案:您可以将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
于 2019-07-29T14:40:09.647 回答
0

我找到了一个解决方案,但我仍然不确定它是好还是坏。但目前它是唯一一个似乎有效的方法。

基本上,我需要在 java args 中添加一堆 --add-opens:

--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() 
于 2020-01-23T20:24:57.763 回答