You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ko...@apache.org on 2005/08/05 07:06:29 UTC

svn commit: r230398 - in /jakarta/commons/sandbox/javaflow/trunk/src: java/org/apache/commons/javaflow/ java/org/apache/commons/javaflow/bytecode/ java/org/apache/commons/javaflow/bytecode/bcel/ test/org/apache/commons/javaflow/

Author: kohsuke
Date: Thu Aug  4 22:06:20 2005
New Revision: 230398

URL: http://svn.apache.org/viewcvs?rev=230398&view=rev
Log:
Moved the implementation detail code from Continuation to StackRecorder.
This allows us to only require one local variable slot for each instrumented method,
and it also allows us to use the Continuation class just for the user-visible methods.

I don't particularly like the name "StackRecorder", though.



Added:
    jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/StackRecorder.java
Modified:
    jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/Continuation.java
    jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/Stack.java
    jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/bcel/BcelClassTransformer.java
    jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTestCase.java
    jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTests.java

Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/Continuation.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/Continuation.java?rev=230398&r1=230397&r2=230398&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/Continuation.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/Continuation.java Thu Aug  4 22:06:20 2005
@@ -15,12 +15,12 @@
  */
 package org.apache.commons.javaflow;
 
-import java.io.Serializable;
-
-import org.apache.commons.javaflow.bytecode.Stack;
+import org.apache.commons.javaflow.bytecode.StackRecorder;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import java.io.Serializable;
+
 /**
  * Snapshot of a thread execution state.
  *
@@ -43,31 +43,14 @@
 
     private final static Log log = LogFactory.getLog(Continuation.class);
     
-    private final static ThreadLocal continuationsMap = new ThreadLocal();
-    private transient Object context;
-
-    private transient boolean restoring = false;
-    private transient boolean capturing = false;
-
-    private final Runnable target;
-
-    private final Stack stack;
-    private final Continuation root;
+    private final StackRecorder stack;
 
     
-    private Continuation(Runnable target) {
-        stack = new Stack();
-        this.target = target;
-        root = this;
-    }
-
     /**
      * Create a new continuation, which continue a previous continuation.
      */
-    private Continuation( final Continuation parent ) {
-        stack = new Stack(parent.stack);
-        target = parent.target;
-        root = parent.root;
+    private Continuation(StackRecorder sr) {
+        stack = sr;
     }
 
 
@@ -86,8 +69,8 @@
      *      null if this method is invoked outside {@link #startWith(Runnable, Object)}
      *      or {@link #continueWith(Continuation, Object)} .
      */
-    public Object getContext() {
-        return context;
+    public static Object getContext() {
+        return StackRecorder.get().getContext();
     }
 
     /**
@@ -125,11 +108,9 @@
             throw new IllegalArgumentException("target is null");
         }
 
-        final Continuation newContinuation = new Continuation(target);
-
         log.debug("starting new flow from " + target);
 
-        return newContinuation.execute(context);
+        return execute(new StackRecorder(target), context);
     }
 
     /**
@@ -167,101 +148,33 @@
 
         log.debug("continueing with continuation " + resumed);
 
-        final Continuation newContinuation = new Continuation(resumed);
-
-        newContinuation.restoring = true;
-        
-        return newContinuation.execute(context);
-    }
-
-    private Continuation execute(final Object context) {
-        boolean completed = false;
-
-        final Continuation runningContinuation = registerThread();
-        try {
-            this.context = context;
-            target.run();
-        } finally {
-            if (capturing) {
-                if (stack.hasReference()) {
-                    stack.popReference();
-                }
-            } else {
-                completed = true;
-            }
-
-            this.context = null;
-            
-            deregisterThread(runningContinuation);
-        }
+        return execute(new StackRecorder(resumed.stack),context);
+    }
 
-        if(completed) {
+    private static Continuation execute(StackRecorder stack, final Object context) {
+        stack = stack.execute(context);
+        if(stack==null) {
             return null;
         } else {
-            return this;
+            return new Continuation(stack);
         }
     }
-    
-    /**
-     * Stop the running continuation.
-     */
-    public static void suspend() {
-        log.debug("suspend()");
-
-        final Continuation continuation = Continuation.currentContinuation();
-
-        if (continuation == null) {
-            throw new IllegalStateException("no continuation is running");
-        }
-        
-        continuation.capturing = !continuation.restoring;
-        
-        continuation.restoring = false;
-    }
 
     /**
-     * True, if the continuation restores the previous stack trace to the last
-     * invocation of suspend().
-     */
-    public boolean isRestoring() {
-        return restoring;
-    }
-
-    /**
-     * True, is the continuation freeze the strack trace, and stops the
-     * continuation.
-     */
-    public boolean isCapturing() {
-        return capturing;
-    }
-
-    public Stack getStack() {
-        return stack;
-    }
-
-    /**
-     * Bind the continuation to running thread.
-     */
-    private Continuation registerThread() {
-        Continuation old = currentContinuation();
-        continuationsMap.set(this);
-        return old;
-    }
-
-    /**
-     * Unbind the continuation to running thread.
+     * Stops the running continuation.
+     *
+     * <p>
+     * This method can be only called inside {@link #continueWith} or {@link #startWith} methods.
+     * When called, the thread returns from the above methods with a new {@link Continuation}
+     * object that captures the thread state.
+     *
+     * @throws IllegalStateException
+     *      if this method is called outside the {@link #continueWith} or {@link #startWith} methods.
      */
-    private void deregisterThread(Continuation old) {
-        continuationsMap.set(old);
+    public static void suspend() {
+        StackRecorder.suspend();
     }
 
-    /**
-     * Return the continuation, which is associated to the current thread.
-     */
-    public static Continuation currentContinuation() {
-        return (Continuation)continuationsMap.get();
-    }
-    
     public String toString() {
         return "Continuation@" + hashCode() + " in " + getClass().getClassLoader();
     }

Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/Stack.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/Stack.java?rev=230398&r1=230397&r2=230398&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/Stack.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/Stack.java Thu Aug  4 22:06:20 2005
@@ -140,6 +140,7 @@
         }
         
         final Object o = ostack[--oTop];
+        ostack[oTop]=null;  // avoid unnecessary reference to object
 
         final String clazz = getClassName(o);
         final String clazzLoader = getClassLoaderName(o);
@@ -159,6 +160,7 @@
         }
         
         final Object o = rstack[--rTop];
+        rstack[rTop]=null;  // avoid unnecessary reference to object
 
         final String clazz = getClassName(o);
         final String clazzLoader = getClassLoaderName(o);
@@ -265,7 +267,11 @@
         
         return String.valueOf(o.getClass().getClassLoader());
     }
-    
+
+    public boolean isEmpty() {
+        return iTop==0 && lTop==0 && dTop==0 && fTop==0 && oTop==0 && rTop==0;
+    }
+
 
     public String toString() {
         return

Added: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/StackRecorder.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/StackRecorder.java?rev=230398&view=auto
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/StackRecorder.java (added)
+++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/StackRecorder.java Thu Aug  4 22:06:20 2005
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.javaflow.bytecode;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Adds additional behaviors necessary for stack capture/restore
+ * on top of {@link Stack}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public final class StackRecorder extends Stack {
+    private final static Log log = LogFactory.getLog(StackRecorder.class);
+    private static final long serialVersionUID = 1L;
+
+    private transient boolean restoring = false;
+    private transient boolean capturing = false;
+
+    /**
+     * Context object given by the user.
+     */
+    private transient Object context;
+
+    private final static ThreadLocal threadMap = new ThreadLocal();
+
+    /**
+     * Creates a new empty {@link StackRecorder} that runs the given target.
+     */
+    public StackRecorder(Runnable target) {
+        pushReference(target);
+    }
+
+    /**
+     * Creates a clone of the given {@link StackRecorder}.
+     */
+    public StackRecorder(final Stack parent) {
+        super(parent);
+    }
+
+    public static void suspend() {
+        log.debug("suspend()");
+
+        StackRecorder r = get();
+        if(r==null) {
+            throw new IllegalStateException("No continuation is running");
+        }
+
+        r.capturing = !r.restoring;
+        r.restoring = false;
+    }
+
+    /**
+     * True, if the continuation restores the previous stack trace to the last
+     * invocation of suspend().
+     */
+    public boolean isRestoring() {
+        return restoring;
+    }
+
+    /**
+     * True, is the continuation freeze the strack trace, and stops the
+     * continuation.
+     */
+    public boolean isCapturing() {
+        return capturing;
+    }
+
+    public StackRecorder execute(final Object context) {
+        final StackRecorder old = registerThread();
+        Runnable target = (Runnable)popReference();
+        try {
+            restoring = !isEmpty(); // start restoring if we have a filled stack
+            this.context = context;
+            target.run();
+            if (!capturing) {
+                return null;
+            }
+        } finally {
+            this.context = null;
+            deregisterThread(old);
+        }
+        return this;
+    }
+
+    public Object getContext() {
+        return context;
+    }
+
+    /**
+     * Bind this stack recorder to running thread.
+     */
+    private StackRecorder registerThread() {
+        StackRecorder old = get();
+        threadMap.set(this);
+        return old;
+    }
+
+    /**
+     * Unbind the current stack recorder to running thread.
+     */
+    private void deregisterThread(final StackRecorder old) {
+        threadMap.set(old);
+    }
+
+    /**
+     * Return the continuation, which is associated to the current thread.
+     */
+    public static StackRecorder get() {
+        return (StackRecorder)threadMap.get();
+    }
+}

Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/bcel/BcelClassTransformer.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/bcel/BcelClassTransformer.java?rev=230398&r1=230397&r2=230398&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/bcel/BcelClassTransformer.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/bcel/BcelClassTransformer.java Thu Aug  4 22:06:20 2005
@@ -32,9 +32,9 @@
 import org.apache.bcel.generic.DUP2_X2;
 import org.apache.bcel.generic.GOTO;
 import org.apache.bcel.generic.IFEQ;
-import org.apache.bcel.generic.IFNONNULL;
 import org.apache.bcel.generic.IFNULL;
 import org.apache.bcel.generic.INVOKESTATIC;
+import org.apache.bcel.generic.Instruction;
 import org.apache.bcel.generic.InstructionConstants;
 import org.apache.bcel.generic.InstructionFactory;
 import org.apache.bcel.generic.InstructionHandle;
@@ -54,10 +54,9 @@
 import org.apache.bcel.generic.TargetLostException;
 import org.apache.bcel.generic.Type;
 import org.apache.bcel.verifier.exc.AssertionViolatedException;
-import org.apache.commons.javaflow.Continuation;
 import org.apache.commons.javaflow.bytecode.ClassTransformer;
-import org.apache.commons.javaflow.bytecode.Stack;
 import org.apache.commons.javaflow.bytecode.Continuable;
+import org.apache.commons.javaflow.bytecode.StackRecorder;
 import org.apache.commons.javaflow.bytecode.bcel.analyser.ControlFlowGraph;
 import org.apache.commons.javaflow.bytecode.bcel.analyser.ExceptionHandler;
 import org.apache.commons.javaflow.bytecode.bcel.analyser.ExecutionVisitor;
@@ -85,13 +84,13 @@
 
     private final static Log log = LogFactory.getLog(BcelClassTransformer.class);
 
-    private static final String CONTINUATION_CLASS = Continuation.class.getName();
-    private static final ObjectType CONTINUATION_TYPE = new ObjectType(CONTINUATION_CLASS);
-    private static final String STACK_CLASS = Stack.class.getName();
-    private static final ObjectType STACK_TYPE = new ObjectType(STACK_CLASS);
+//    private static final String CONTINUATION_CLASS = Continuation.class.getName();
+//    private static final ObjectType CONTINUATION_TYPE = new ObjectType(CONTINUATION_CLASS);
+    private static final String STACK_RECORDER_CLASS = StackRecorder.class.getName();
+    private static final ObjectType STACK_RECORDER_TYPE = new ObjectType(STACK_RECORDER_CLASS);
     private static final String CONTINUABLE_CLASS = Continuable.class.getName();
-    private static final String CONTINUATION_METHOD = "currentContinuation";
-    private static final String STACK_METHOD = "getStack";
+//    private static final String CONTINUATION_METHOD = "currentContinuation";
+    private static final String STACK_METHOD = "get";
     private static final String POP_METHOD = "pop";
     private static final String PUSH_METHOD = "push";
     private static final String RESTORING_METHOD = "isRestoring";
@@ -356,7 +355,7 @@
         final InstructionList insList = method.getInstructionList();
         InstructionHandle ins = insList.getStart();
         final InstructionList restorer = new InstructionList();
-        int count = 0;
+        int count = 0;  // count # of breakpoints
         
         while (ins != null) {
             InstructionHandle next = ins.getNext();
@@ -434,6 +433,12 @@
             }
             ins = next;
         }
+
+        // local variable index for storing the StackRecorder object
+        final int varStack = method.getMaxLocals();
+        // instruction to load the stack recorder
+        Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, varStack);
+
         final InstructionHandle firstIns = insList.getStart();
         if (count > 0) {
             final InstructionHandle[] tableTargets = new InstructionHandle[count];
@@ -446,59 +451,47 @@
 
             // select frame restorer
             insList.insert(new TABLESWITCH(match, tableTargets, firstIns));
-            insList.insert(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.INT), Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
-            insList.insert(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+            insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.INT), Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+            insList.insert(loadStackRecorder);
 
             // test if the continuation should be restored
             insList.insert(new IFEQ(firstIns));
-            insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, RESTORING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
-            insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
-        }
+            insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, RESTORING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+            insList.insert(loadStackRecorder);
 
-        // get stack from current continuation and store in the last local
-        // variable
-        insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals() + 1));
-        insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, STACK_METHOD, STACK_TYPE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
-        final InstructionHandle restore_handle = insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
-
-        // if not continuation exists, create empty stack
-        insList.insert(new GOTO(firstIns));
-        insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals() + 1));
-        insList.insert(insFactory.createInvoke(STACK_CLASS, Constants.CONSTRUCTOR_NAME, Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
-        insList.insert(InstructionFactory.createDup(STACK_TYPE.getSize()));
-        insList.insert(insFactory.createNew(STACK_TYPE));
-
-        // test if no current continuation exists
-        insList.insert(new IFNONNULL(restore_handle));
-        insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
-
-        // get current continuation and store in the next to last local variable
-        insList.insert(InstructionFactory.createStore(CONTINUATION_TYPE, method.getMaxLocals()));
-        insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, CONTINUATION_METHOD, CONTINUATION_TYPE, Type.NO_ARGS, Constants.INVOKESTATIC));
-
-        // make room for additional objects
-        method.setMaxLocals(method.getMaxLocals() + 2);
-        method.setMaxStack(method.getMaxStack() + 2);
+            // test if no current continuation exists
+            insList.insert(new IFNULL(firstIns));
+
+            // get current continuation and store in the next to last local variable
+            insList.insert(InstructionFactory.createStore(STACK_RECORDER_TYPE, varStack));
+            insList.insert(InstructionConstants.DUP);
+            insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, STACK_METHOD, STACK_RECORDER_TYPE, Type.NO_ARGS, Constants.INVOKESTATIC));
+
+            // make room for additional object (StackRecorder)
+            method.setMaxLocals(method.getMaxLocals() + 1);
+            method.setMaxStack(method.getMaxStack() + 2);
+        }
     }
 
-    private InstructionList duplicateStack(MethodGen method, InvokeInstruction invoke, ObjectType objecttype) throws ClassNotFoundException {
+    private InstructionList duplicateStack(MethodGen method, InvokeInstruction invoke, ObjectType objecttype) {
         // reconstruction of an uninitialed object to call the constructor.
         final InstructionFactory insFactory = new InstructionFactory(method.getConstantPool());
         final InstructionList insList = new InstructionList();
 
         final Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
         // pop all arguments for the constructor from the stack
+        Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, method.getMaxLocals());
         for (int i = arguments.length - 1; i >= 0; i--) {
             Type type = arguments[i];
-            insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+            insList.append(loadStackRecorder);
             insList.append(new SWAP());
             if (type instanceof BasicType) {
                 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
                     type = Type.INT;
                 }
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
             } else if (type instanceof ReferenceType) {
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
             }
         }
         // create uninitialzed object
@@ -507,14 +500,14 @@
         // return the arguments into the stack
         for (int i = 0; i < arguments.length; i++) {
             Type type = arguments[i];
-            insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+            insList.append(loadStackRecorder);
             if (type instanceof BasicType) {
                 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
                     type = Type.INT;
                 }
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
             } else if (type instanceof ReferenceType) {
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
                 if (!type.equals(Type.OBJECT)) {
                     insList.append(insFactory.createCast(Type.OBJECT, type));
                 }
@@ -523,7 +516,7 @@
         return insList;
     }
 
-    private boolean rewriteable(MethodGen method, InstructionHandle handle) throws ClassNotFoundException {
+    private boolean rewriteable(MethodGen method, InstructionHandle handle) {
         // check in the invocation can be a breakpoint.
         int opcode = handle.getInstruction().getOpcode();
         boolean invokeSpecialSuper = false;
@@ -562,7 +555,10 @@
         //if (debug) {
         //    insList.append(insFactory.createPrintln("save stack"));
         //}
-        
+
+        // instruction for loading StackRecorder
+        Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, method.getMaxLocals());
+
         // save stack
         final OperandStack os = frame.getStack();
         for (int i = skipFirst ? 1 : 0; i < os.size(); i++) {
@@ -575,14 +571,14 @@
                 // check for types with two words on stack
                 if (type.equals(Type.LONG) || type.equals(Type.DOUBLE)) {
                     insList.append(new ACONST_NULL()); // create dummy stack entry
-                    insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1));
+                    insList.append(loadStackRecorder);
                     insList.append(new DUP2_X2()); // swap Stack object and long/float
                     insList.append(new POP2());
                 } else {
-                    insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1));
+                    insList.append(loadStackRecorder);
                     insList.append(new SWAP());
                 }
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
                 if (type.equals(Type.LONG) || type.equals(Type.DOUBLE))
                     insList.append(new POP()); // remove dummy stack entry
             } else if (type == null) {
@@ -591,9 +587,9 @@
                 // After the remove of new, there shouldn't be a
                 // uninitialized object on the stack
             } else if (type instanceof ReferenceType) {
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+                insList.append(loadStackRecorder);
                 insList.append(new SWAP());
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
             }
         }
         // add isCapturing test
@@ -603,13 +599,13 @@
         insList.insert(new IFEQ(handle.getNext()));
         
         // test if the continuation should be captured after the invocation
-        insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, CAPURING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
-        insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
+        insList.insert(insFactory.createInvoke(STACK_RECORDER_CLASS, CAPURING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+        insList.insert(loadStackRecorder);
         
         // test if continuation exists
         insList.insert(new IFNULL(handle.getNext()));
-        insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
-        
+        insList.insert(loadStackRecorder);
+
         // save local variables        
         //if (debug) {
         //    insList.append(insFactory.createPrintln("save local variables"));
@@ -619,11 +615,11 @@
         for (int i = 0; i < lvs.maxLocals(); i++) {
             Type type = lvs.get(i);
             if (type instanceof BasicType) {
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+                insList.append(loadStackRecorder);
                 insList.append(InstructionFactory.createLoad(type, i));
                 if (type.getSize() < 2 && !type.equals(Type.FLOAT))
                     type = Type.INT;
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(type), Type.VOID, new Type[] { type }, Constants.INVOKEVIRTUAL));
             } else if (type == null) {
                 // no need to save null
             } else if (type instanceof UninitializedObjectType) {
@@ -631,19 +627,19 @@
             } else if (type instanceof ReferenceType) {
                 if (i == 0 && !currentMethodStatic) {
                     // remember current object
-                    insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+                    insList.append(loadStackRecorder);
                     insList.append(InstructionFactory.createLoad(type, i));
-                    insList.append(insFactory.createInvoke(STACK_CLASS, PUSH_METHOD + "Reference", Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
+                    insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, PUSH_METHOD + "Reference", Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
                 }
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+                insList.append(loadStackRecorder);
                 insList.append(InstructionFactory.createLoad(type, i));
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.OBJECT), Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
             }
         }
         // save programcounter
-        insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+        insList.append(loadStackRecorder);
         insList.append(new PUSH(method.getConstantPool(), pc));
-        insList.append(insFactory.createInvoke(STACK_CLASS, getPushMethod(Type.INT), Type.VOID, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
+        insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPushMethod(Type.INT), Type.VOID, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
         // return NULL result
         insList.append(InstructionFactory.createNull(method.getReturnType()));
         insList.append(InstructionFactory.createReturn(method.getReturnType()));
@@ -658,14 +654,16 @@
         //}
         
         final LocalVariables lvs = frame.getLocals();
+        Instruction loadStackRecorder = InstructionFactory.createLoad(STACK_RECORDER_TYPE, method.getMaxLocals());
+
         for (int i = lvs.maxLocals() - 1; i >= 0; i--) {
             Type type = lvs.get(i);
             if (type instanceof BasicType) {
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
+                insList.append(loadStackRecorder);
                 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
                     type = Type.INT;
                 }
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
                 insList.append(InstructionFactory.createStore(type, i));
             } else if (type == null) {
                 insList.append(new ACONST_NULL());
@@ -674,8 +672,8 @@
                 // No uninitilaized objects should be found
                 // in the local variables.
             } else if (type instanceof ReferenceType) {
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(loadStackRecorder);
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
                 if (!type.equals(Type.OBJECT) && (!type.equals(Type.NULL))) {
                     insList.append(insFactory.createCast(Type.OBJECT, type));
                 }
@@ -699,24 +697,24 @@
                 if (type.getSize() < 2 && !type.equals(Type.FLOAT)) {
                     type = Type.INT;
                 }
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(loadStackRecorder);
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(type), type, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
             } else if (type == null) {
                 insList.append(new ACONST_NULL());
             } else if (type instanceof UninitializedObjectType) {
                 // After the remove of new, there shouldn't be a
                 // uninitialized object on the stack
             } else if (type instanceof ReferenceType) {
-                insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
-                insList.append(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+                insList.append(loadStackRecorder);
+                insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, getPopMethod(Type.OBJECT), Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
                 if (!type.equals(Type.OBJECT))
                     insList.append(insFactory.createCast(Type.OBJECT, type));
             }
         }
         // retrieve current object
         if (!(inv instanceof INVOKESTATIC)) {
-            insList.append(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals() + 1));
-            insList.append(insFactory.createInvoke(STACK_CLASS, POP_METHOD + "Reference", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+            insList.append(loadStackRecorder);
+            insList.append(insFactory.createInvoke(STACK_RECORDER_CLASS, POP_METHOD + "Reference", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
             insList.append(insFactory.createCast(Type.OBJECT, objecttype));
         }
         // Create null types for the parameters of the method invocation

Modified: jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTestCase.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTestCase.java?rev=230398&r1=230397&r2=230398&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTestCase.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTestCase.java Thu Aug  4 22:06:20 2005
@@ -35,4 +35,8 @@
         call("testIncorrectUsageWithNormalClassLoader");
     }    
 
+    public void testCouner() throws Exception {
+        call("testCounter");
+    }
+
 }

Modified: jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTests.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTests.java?rev=230398&r1=230397&r2=230398&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTests.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/test/org/apache/commons/javaflow/ContinuationTests.java Thu Aug  4 22:06:20 2005
@@ -21,6 +21,7 @@
 import junit.framework.TestCase;
 
 import org.apache.commons.javaflow.testcode.Calculator;
+import org.apache.commons.javaflow.testcode.Counter;
 import org.apache.commons.javaflow.utils.ReflectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -82,5 +83,11 @@
         }
         
         TestCase.assertTrue(exceptionThrown);
+    }
+
+    public void testCounter() throws Exception {
+        Counter runner = new Counter(5);
+        for(Continuation c=Continuation.startWith(runner); c!=null; c=Continuation.continueWith(c))
+            System.out.println("resuming");
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org