简体   繁体   中英

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

I want to be able to capture a continuation and resume it several times, such that each such invocation would be independent of the others.

For example, in the following code, I'd want the 2 calls to context.resumeContinuation in the run method to result in the output: 1 1 , rather than the current output of 1 2 .

As far as I understand, the reason for the resulting output is that I always use the same scope object, which is being modified by the first continuation before being passed to the second one. So it seems that I should resume each continuation with a copy of the original scope , but type Scriptable has no clone method (or anything equivalent), and copying it using serialization/deserialization doesn't help either.

PS I am using Rhino version 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;

So I came up with a working solution:

Instead of copying the scope object, I should've copied the capturedContinuation object, so the 2 calls to resumeContinuation would be:

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

This question offers possible imeplementations of the deepCopy method.

A word of caution, though: instances of Rhino's NativeContinuation type (which is the dynamic type of capturedContinuation in the code above) seem to be quite large (~15KB and up when serialized to a byte array), so time/memory consumption implications should be considered when deep copying them in an application.

This is just a guess but I think this might work (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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM