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.