First, I'm glad to hear more input ;-) Your mail took some time
to parse it.
Am Mo, den 05.04.2004 schrieb Christopher Oliver um 18:47:
> OK, IIUC there are three modes of execution of the instrumented code:
>
> 1) isCapturing
> During this mode the JVM call stack is unwound and its state captured in
> the continuation call stack.
> 2) isRestoring
> During this mode a saved call stack in a continuation is recreated on
> the JVM stack.
> 3) !isCapturing && !isRestoring
> This is the "normal" execution of the JVM - no modifications are made
> to the JVM call stack or to the continuation call stack.
Correct.
> This is achieved by inserting code before each invoke instruction to
> copy local variables from the continuation stack to the JVM stack and to
> reset the program counter to the value saved in the continuation stack
> if "isRestoring" is true, and by inserting code after each invoke
> instruction to copy the values of local variables from the JVM call
> stack as well as the program counter into the continuation call stack if
> "isCapturing" is true.
Yes, but the code for the restore procedure is at the begining of the
method not the before the invocation, but anyway..
I need some pseudo code for myself ;-) Current situation:
void myFlow() {
if (continuation.isRestoring()) {
continuation.getStack().popLocalVariables();
continuation.getStack().popOperandStack();
continuation.getStack().popReference(); // used for the
//method invocation
push(null) as many null object as the method invovation need for
the parameters
goto continuation.getStack().popLastProcessCounter();
}
[...]
label 1:
invoke MySubFlow.bla();
if (continuation.isCapturing() {
remove the return value (is unimportant)
continuation.getStack().pushLocalVariables();
continuation.getStack().pushOperandStack();
continuation.getStack().pushLastProcessCounter(label 1);
continuation.getStack().pushReference(this);
return null or void;
}
[...]
}
> To make continuations more "Scheme-like" it must be possible to
> construct a continuation without modifying the JVM call stack (thus the
> current method invocation can "continue as normal").
>
> To make this possible the byte-code transformer could work like this:
> 1) Insert code before an invoke instruction to push local vars and the
> pc onto the continuation stack if (!isRestoring && !isCapturing)
> 2) Insert code after an invoke instruction to pop those values from the
> continuation stack if (!isRestoring && !isCapturing)
> 3) If (isRestoring == true) the pre-invoke code would work as it does now.
> 4) If (isCapturing == true) the post-invoke code would simply cause the
> current method invocation to return to its caller without modifying the
> continuation stack - since it is already set up from (1). When the JVM
> stack is completely unwound another continuation will take the place of
> this one and that new continuation would be in "isRestoring" mode until
> it is recreated on the JVM stack at which point it would enter
> (!isRestoring && !isCapturing) mode.
Okay to recapitulate IIUC. Your proposal:
void myFlow() {
if (continuation.isRestoring()) {
continuation.getStack().popLocalVariables();
continuation.getStack().popOperandStack();
goto continuation.getStack().popLastProcessCounter();
}
[...]
continuation.getStack().pushLocalVariables();
continuation.getStack().pushOperandStack();
continuation.getStack().pushLastProcessCounter(label 1);
label 1:
invoke MySubFlow.bla();
if (continuation.isCapturing() {
return null or void;
} else {
continuation.getStack().popLocalVariables();
continuation.getStack().popOperandStack();
continuation.getStack().popLastProcessCounter();
}
[...]
}
Yes, this has the benefit to call "uninstrumented" code, but
the complete frame must be captured and restored for every invocation.
> The user interface to this might look something like this:
>
> public class Continuation {
> // Empty continuation for use as an escape procedure
> public static final Continuation SUICIDE;
I didn't get the role of SUICIDE.
> // Invoke a captured continuation - it will replace the current
> continuation. I.e. the current JVM call stack will be unwound, the call
> stack saved in this object will be recreated on the JVM call stack, and
> the method invocation in which this object was created will return with
> "returnValue".
> public void invoke(Object returnValue);
Do you want to use the "returnValue" to return the WebContinuation in
sendPageAndWait() ? The problem I see is that you suspend the thread
at a method invocation not at the end of the method.
> // Get the current continuation -
> public static Continuation getCurrentContinuation();
> // Entry point to the instrumented code (precondition: cannot be
> called recursively and method.getDeclaringClass() must be instrumented)
> public static Object invoke(Object obj, Method method, Object[]
> args);
> }
Why don't use (Object obj, Method method, Object[] args) in the
constructor of the continuation object.
Something like that:
// Start continuation
Continuation c = new Continuation(Object obj, Method method, Object[]
args)
c.invoke();
if (c.isSusended()) {
// Continue the continuation
c = new Continuation(c);
c.continue();
}
> public class Cocoon {
> // ...
> public WebContinuation sendPageAndWait(String uri, Object biz, long
> ttl) {
> Continuation kont = Continuation.getCurrentContinuation();
> WebContinuation wk =
> continuationsMgr.createWebContinuation(kont,
> parentWebContinuation,
> ttl,
> null);
> sendPage(uri, biz);
> Continuation.SUICIDE.invoke(null);
> return wk; // never reached
> }
Continuation.SUICIDE.invoke(null); ?
*you see many question marks over my head*
I hope you have patience with me :)
Stephan Michels.