是否可以在 Rhino 中多次恢复延续?

Is it possible to resume a continuation in Rhino multiple times?

我希望能够捕获一个延续并多次恢复它,这样每个这样的调用都将独立于其他调用。

例如,在下面的代码中,我希望在 run 方法中对 context.resumeContinuation 的 2 次调用产生输出:1 1,而不是当前的1 2.

的输出

据我了解,产生结果输出的原因是我总是使用相同的 scope 对象,该对象在传递给第二个之前由第一个延续进行修改。所以看来我应该用原始 scopecopy 恢复每个延续,但是类型 Scriptable 没有clone 方法(或任何等效方法),并使用 serialization/deserialization 复制它也无济于事。

P.S. 我用的是 Rhino 1.7R5.

Example.java:

import org.mozilla.javascript.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Example {
    public void run() throws IOException {
        Context context = Context.enter();
        context.setOptimizationLevel(-2);   // Use interpreter mode.
        Scriptable scope = context.initStandardObjects();
        scope.put("javaProxy", scope, Context.javaToJS(this, scope));

        Object capturedContinuation = null;
        try {
            String scriptSource =
                new String(Files.readAllBytes(Paths.get("example.js")));

            String scriptName = "example";
            int startLine = 1;
            Object securityDomain = null;
            Script script =
                context.compileString(scriptSource, scriptName, startLine, securityDomain);
            context.executeScriptWithContinuations(script, scope);
        } catch (ContinuationPending continuationPending) {
            capturedContinuation = continuationPending.getContinuation();
        }

        Object result = "";

        context.resumeContinuation(capturedContinuation, scope, result);
        context.resumeContinuation(capturedContinuation, scope, result);

        Context.exit();
    }

    public void captureContinuation() {
        Context context = Context.enter();
        ContinuationPending continuationPending =
            context.captureContinuation();
        Context.exit();
        throw continuationPending;
    }

    public void print(int i) {
        System.out.print(i + " ");
    }

    public static void main(String[] args) throws IOException {
        new Example().run();
    }
}

example.js:

var i = 1;
javaProxy.captureContinuation();
javaProxy.print(i);
i = i + 1;

所以我想出了一个可行的解决方案:

我应该复制 capturedContinuation 对象而不是复制 scope 对象,因此对 resumeContinuation 的 2 次调用将是:

context.resumeContinuation(deepCopy(capturedContinuation), scope, result);
context.resumeContinuation(deepCopy(capturedContinuation), scope, result);

This question 提供了 deepCopy 方法的可能实现。

但请注意:Rhino 的 NativeContinuation 类型实例(即上面代码中 capturedContinuation 的动态类型)似乎相当大(序列化时约 15KB 或更大)到字节数组),因此 time/memory 在应用程序中深度复制它们时应考虑消耗影响。

这只是一个猜测,但我认为这可能有效 (Rhino 1.7.6):

    NativeContinuation capturedContinuation = ...
    final Object stackFrame = capturedContinuation.getImplementation();

    // Invoke once...
    context.resumeContinuation(capturedContinuation, scope, result);

    // Put stack back where it was
    capturedContinuation.initImplementation(stackFrame);

    // Invoke twice...
    context.resumeContinuation(capturedContinuation, scope, result);