cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Christopher Oliver <res1c...@verizon.net>
Subject Re: Scheme Continuations vs Brakes Continuations was Re: Groovy support in Cocoon
Date Mon, 05 Apr 2004 20:44:16 GMT
Stephan Michels wrote:

>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..
>  
>
Yes, of course. Sorry for not being more accurate.

>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;
>  }
>
>  [...]
>}
>
>  
>
OK.

>>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.
>
>  
>
See my second message regarding this.

>>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.
>
>  
>
That's a possible alternative, but makes prevents making Continuation an 
abstract class.

>Continuation.SUICIDE.invoke(null); ?
>
>*you see many question marks over my head*
>
>I hope you have patience with me :)
>
>  
>
The idea of SUICIDE is that it has the effect of unwinding the stack but 
not executing any further code and directly returns to the entry point 
(i.e. it is the continuation of the end of some code ). For example (in JS):

var suicide;

function f() {
   suicide = arguments.continuation;
}

f();  // <== since there's no code to execute after f(), invoking 
suicide later will have the effect of simply terminating the script.
// end of script


In the current Rhino implementation creating a Continuation in a 
top-level script has the same effect (since what comes after the end of 
the script is - nothing).

This behavior is as in Scheme.

Chris

Mime
View raw message