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.
P.S. 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.