[javaflow] MethodLookup

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

[javaflow] MethodLookup

Kohsuke Kawaguchi
I'm bit confused with MethodLookup. I could be just missing something,
but here it goes...


I wonder if it would be better if the startWith method is:

Continuation startWith( Runnable target, ContinuationContext context )

... instead of:

Continuation startWith( String methodName, ContinuationContext context )

... where the semantics is that the execution starts by invoking the
run() method of the target object.

I think developers relates to Runnable more easily, as java.lang.Thread
uses it. I also think there isn't any loss in the expressiveness of the
library, as we can emulate the old functionality by using a Runnable
that looks up a method name from String and create a new instance.

This approach allows me to fill in the Runnable object by application
specific information. This is analogous to how one would pass
information to a newly launched java.lang.Thread.

I think reducing the developer-visible surface of javaflow by exploiting
the core JDK libraries makes javaflow easier to use.

It also has some other minor benefits, like simplifying the
implementation and improving the performance by avoiding reflection.

--
Kohsuke Kawaguchi

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi-2
Kohsuke Kawaguchi wrote:
> I'm bit confused with MethodLookup. I could be just missing something,
> but here it goes...

I should have mentioned that I've already read [1] before writing this
e-mail.

[1] http://vafer.org/blog/tcurdt/archives/2005_02.html
--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Torsten Curdt
In reply to this post by Kohsuke Kawaguchi

On 27.07.2005, at 07:11, Kohsuke Kawaguchi wrote:

> I'm bit confused with MethodLookup. I could be just missing  
> something, but here it goes...
>

The MethodLookup was introduced when I added the
serialization support. Beforehand the Method was
passed in directly. But now the Method that is
stored inside the Continuation is marked transient.
After the resume the Method is null and must be
looked up.

> I wonder if it would be better if the startWith method is:
>
> Continuation startWith( Runnable target, ContinuationContext context )

I've been thinking about that, too ...but for the
use inside Cocoon I don't really want to restrict
it to the "void run()" method only.

Besides for the serialization support we would
need to pass in the Runnable/Method also for
"continueWith(Runnable/Method, Continuation)"

IIRC there were even more reasons ...will try
to remember :)

> I think developers relates to Runnable more easily, as  
> java.lang.Thread uses it. I also think there isn't any loss in the  
> expressiveness of the library, as we can emulate the old  
> functionality by using a Runnable that looks up a method name from  
> String and create a new instance.

Uh... that sounds ugly :)

...but how about the other way around. We could
also provide

  Continuation startWith(ContinuationContext) // means: use method "run"
  Continuation startWith(String, ContinuationContext)

with a standard ContinuationContext that explicitly
supports a Runnable by providing a default implementation.
So a bit simplified you could do:

   startWith(new DefaultContinuationContext(Runnable))

That would give us all the flexibility and the simplified
interface

WDYT?


> It also has some other minor benefits, like simplifying the  
> implementation and improving the performance by avoiding reflection.

As the reflection calls are cached the performance impact
is really minor.

cheers
--
Torsten

PGP.sig (193 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi
Thank you for a quick response and listening to my suggestion.


Torsten Curdt wrote:

> ..but how about the other way around. We could
> also provide
>
>   Continuation startWith(ContinuationContext) // means: use method "run"
>   Continuation startWith(String, ContinuationContext)
>
> with a standard ContinuationContext that explicitly
> supports a Runnable by providing a default implementation.
> So a bit simplified you could do:
>
>    startWith(new DefaultContinuationContext(Runnable))
>
> That would give us all the flexibility and the simplified
> interface
>
> WDYT?

If I understand this correctly, for me to capture the continuation and
run it later, I do:

        Runnable myRunnable = new MyRunnable(...);
        Continuation  c = Continuation.startWith(
          new DefaultContinuationContext(myRunnable))

        // serialize the continuation
        ObjectOutputStream oos = ...;
        oos.writeObject(c);
        oos.writeObject(myRunnable);

/* later */
        ObjectInputStream ois = ...;
        Continuation c = ois.readObject();
        Runnable myRunnable = ois.readObject();

        c.continueWith(new DefaultContinuationContext(myRunnable));

is that correct? (I'm assuming that you designed ContinuationContext to
keep track of things you want to change between runs, so it's not
reachable from Continuation if it's not executing.)

I thought it would be nice if I can write it instead as:

        Runnable myRunnable = new MyRunnable(...);
        Continuation  c = Continuation.startWith(myRunnable,null);

        // serialize the continuation
        ObjectOutputStream oos = ...;
        oos.writeObject(c);

/* later */
        ObjectInputStream ois = ...;
        Continuation c = ois.readObject();

        c.continueWith(null);


Or maybe what I really wanted was to the "ContinuableThread" class or
something that wraps the existing API into a class that feels like
java.lang.Thread, so that I can do:

        ContinuableThread t = new ContinuableThread() {
          // override run or pass in Runnable to the constructor
          void run() { ...; suspend(); ...; }
        }

        t.start(); // start running. return when suspended

        oos.writeObject(t); // serialize
        t = ois.readObject(); // deserialize
        t = t.clone(); // AKA thread fork

        while(t.isAlive())
                t.continue();

If I wanted to do the equivalent of the ContinuationContext, I can
define a field in my derived class and set if every time before I call
continue.

I can implement this on top of existing javaflow code without changing
them. Does this work with you?

--
Kohsuke Kawaguchi

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Torsten Curdt
> If I understand this correctly, for me to capture the continuation and
> run it later, I do:

Have a look into the serialization testcase

>     // serialize the continuation
>     ObjectOutputStream oos = ...;
>     oos.writeObject(c);
>     oos.writeObject(myRunnable);

Since the resume will only work with the
exact same class there is no point in
making the runnable serializable and
saving it.


>     c.continueWith(new DefaultContinuationContext(myRunnable));
>
> is that correct?


Correct - except for the serialization of the
runnable.

> (I'm assuming that you designed ContinuationContext to
> keep track of things you want to change between runs, so it's not  
> reachable from Continuation if it's not executing.)

Sorry, did not get that ..what do you mean?

The ContinuationContext holds all the references
that are required to restore the state but cannot
really be part of the continuation. Logger,
ComponentManager and things like that.

See the example in my blog ...which is actually
taken from the Cocoon integration. (I think in
there is also the link to the class) Would be
great if you could also have a look into that
class.

> I thought it would be nice if I can write it instead as:
>
>     Runnable myRunnable = new MyRunnable(...);
>     Continuation  c = Continuation.startWith(myRunnable,null);

Did understand that ...but that restricts the
API a bit too much. With the propose way we
can have the best of both worlds - I think.

> Or maybe what I really wanted was to the "ContinuableThread" class  
> or something that wraps the existing API into a class that feels  
> like java.lang.Thread, so that I can do:
>
>     ContinuableThread t = new ContinuableThread() {
>       // override run or pass in Runnable to the constructor
>       void run() { ...; suspend(); ...; }
>     }
>
>     t.start();    // start running. return when suspended
>
>     oos.writeObject(t);    // serialize
>     t = ois.readObject();    // deserialize
>     t = t.clone();        // AKA thread fork
Don't understand the cloning.

>     while(t.isAlive())
>         t.continue();

Hmmm... looks interesting but you would
need to poll the continuations. So you
would have to start the "thread" with
every resume ..that's a bit awkward.

cheers
--
Torsten

PGP.sig (193 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi-2
Torsten Curdt wrote:
>> If I understand this correctly, for me to capture the continuation and
>> run it later, I do:
>
> Have a look into the serialization testcase

Thanks. I did some experiments. I think I have misunderstood the way the
stack restoration works. It seems like it's actually replacing local
variable #0 (the 'this' pointer.)

This is interesting. I didn't know that you can do this in Java (I guess
you can do it in JVM, just not in Java language.)





>> (I'm assuming that you designed ContinuationContext to
>> keep track of things you want to change between runs, so it's not  
>> reachable from Continuation if it's not executing.)
>
> Sorry, did not get that ..what do you mean?
>
> The ContinuationContext holds all the references
> that are required to restore the state but cannot
> really be part of the continuation. Logger,
> ComponentManager and things like that.
Yes, I think we are saying the same thing. Pardon my poor English.


> See the example in my blog ...which is actually
> taken from the Cocoon integration. (I think in
> there is also the link to the class) Would be
> great if you could also have a look into that
> class.

I looked at Cocoon code you had in [1]. I didn't particularly see
anything that made me rethink (IOW, I don't see anything that absolutely
requires MethodLookup nor ContinuationContext instead of Runnable.)

But at the same time, I saw that you have some existing investments with
the current javaflow Continuation API and it's very understandable that
you don't want it to change.

I see the desire to pass some contextual information to the invoked
method, but that is a fairly common requirement even if you aren't using
javaflow at all. javaflow just keeps it and stores it somewhere for
later retrieval, which can be better done by the code that knows what
the scope of a given context object is (like ThreadLocal, singleton,
HttpSession, etc.)


Just to make sure that I'm not missing something, I rewrote the
JavaInterpreter and CocoonContinuationContext by using the
ContinuationThread class (which I renamed to Fiber) instead of the
current Continuation API. The only difference is that you now do:

CocoonContinuationContext.getCurrent()

instead of:

(CocoonContinuationContext)Continuation.currentContinuation().getContext()

See the attachments for the exact code. All in all, I didn't think this
re-write is ugly, but that is always a subjective issue.


Anyway, I'm no longer too keen about convincing you to change the API of
the Continuation class. If you like my rewrite, that's good, but if not,
that's also fine with me. The current Continuation API makes the Fiber
class implementation uglier, but that's not too big a problem.

Instead, I'm hoping that you allow me to commit this Fiber class to
javaflow, as this is what I primarily want to use in my code.



[1] http://svn.apache.org/repos/asf/cocoon/blocks/javaflow/trunk/
--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

/*
 * 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.cocoon.components.flow.java;

import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.cocoon.environment.Redirector;
import org.apache.commons.javaflow.ContinuationContext;
import org.apache.commons.javaflow.Fiber;

/**
 * Helper class to associate cocoon flow informations to the continuation.
 *
 * @author <a href="mailto:[hidden email]">Torsten Curdt</a>
 * @author <a href="mailto:[hidden email]">Stephan Michels</a>
 * @version CVS $Id: CocoonContinuationContext.java 151736 2005-02-07 18:29:10Z tcurdt $
 */
public class CocoonContinuationContext {

    private static final ThreadLocal context = new ThreadLocal();

    public static CocoonContinuationContext getCurrent() {
        return (CocoonContinuationContext)context.get();
    }

    private Logger logger;
    private Context avalonContext;
    private ServiceManager manager;
    private Redirector redirector;
   
    private Parameters parameters;

    public void setAvalonContext(Context avalonContext) {
        this.avalonContext = avalonContext;
    }

    public Context getAvalonContext() {
        return avalonContext;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public Logger getLogger() {
        return logger;
    }
   
    public void setServiceManager(ServiceManager manager) {
        this.manager = manager;
    }

    public ServiceManager getServiceManager() {
        return manager;
    }

    public void setRedirector(Redirector redirector) {
        this.redirector = redirector;
    }
 
    public Redirector getRedirector() {
        return redirector;
    }
   
        public Parameters getParameters() {
                return parameters;
        }
       
        public void setParameters(Parameters parameters) {
                this.parameters = parameters;
        }


    /*package*/ void register() {
        context.set(this);
    }

    /*package*/ void unregister() {
        context.set(null);
    }
}

/*
 * 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.cocoon.components.flow.java;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.components.flow.AbstractInterpreter;
import org.apache.cocoon.components.flow.FlowHelper;
import org.apache.cocoon.components.flow.InvalidContinuationException;
import org.apache.cocoon.components.flow.WebContinuation;
import org.apache.cocoon.environment.Redirector;
import org.apache.commons.javaflow.ContinuationCapable;
import org.apache.commons.javaflow.Fiber;
import org.apache.commons.javaflow.utils.ReflectionUtils;
import org.apache.commons.jxpath.JXPathIntrospector;

/**
 * Implementation of the java flow interpreter.
 *
 * @author <a href="mailto:[hidden email]">Stephan Michels</a>
 * @author <a href="mailto:[hidden email]">Torsten Curdt</a>
 * @version CVS $Id: JavaInterpreter.java 151736 2005-02-07 18:29:10Z tcurdt $
 */
public final class JavaInterpreter extends AbstractInterpreter {

    private int timeToLive = 600000;

    static {
        JXPathIntrospector.registerDynamicClass(VarMap.class, VarMapHandler.class);
    }


    private Map methods = new HashMap();

    /**
     * Used to invoke the method specified.
     *
     * This class is continuation capable without instrumentation.
     */
    private static class Invoker implements Runnable, ContinuationCapable {
        private final Method method;
        private final Object instance;

        public Invoker(Method method) throws IllegalAccessException, InstantiationException {
            this.method = method;
            this.instance = method.getDeclaringClass().newInstance();
        }

        public void run() {
            try {
                method.invoke(instance,new Object[0]);
            } catch (IllegalAccessException e) {
                // TODO: log the error
            } catch (InvocationTargetException e) {
                // TODO: log the error
            }
        }
    }

    private CocoonContinuationContext createContinuationContext( final List params, final Redirector redirector ) {
        final CocoonContinuationContext context = new CocoonContinuationContext();
       
        context.setAvalonContext(avalonContext);
        context.setLogger(getLogger());
        context.setServiceManager(manager);
        context.setRedirector(redirector);

        final Parameters parameters = new Parameters();
        for(final Iterator i = params.iterator(); i.hasNext();) {
            final Argument argument = (Argument)i.next();
            parameters.setParameter(argument.name, argument.value);
        }
        context.setParameters(parameters);
       
        return context;
    }
   
   
    private void updateMethodIndex() throws ClassNotFoundException {
        final Map methods = new HashMap();

        for (final Iterator it = needResolve.iterator(); it.hasNext();) {
            final String clazzName = (String) it.next();

            if (getLogger().isDebugEnabled()) {
                getLogger().debug("loading " + clazzName);
            }        

            final Class clazz = Thread.currentThread().getContextClassLoader().loadClass(clazzName);
           
            final Map m = ReflectionUtils.discoverMethods(
                    clazz,
                    new ReflectionUtils.DefaultMatcher(),
                    new ReflectionUtils.Indexer() {
                        public void put(final Map pMap, final String pKey, final Object pObject) {
                            final Method method = (Method) pObject;
                           
                            final String fullName = method.getDeclaringClass().getName() + "." + method.getName();
                            final String shortName = method.getName();
                           
                            pMap.put(shortName, method);
                            pMap.put(fullName, method);

                            if (getLogger().isDebugEnabled()) {
                                getLogger().debug("registered method " + shortName + ", " + fullName);
                            }        
                        }
                    }
                    );

            for (Iterator i = m.entrySet().iterator(); i.hasNext(); ) {
                final Map.Entry e = (Map.Entry) i.next();
               
                if (getLogger().isWarnEnabled()) {
                    if (methods.containsKey(e.getKey())) {
                            getLogger().warn("method name clash for " + e.getKey());
                       
                    }
                }        
               
                methods.put(e.getKey(), e.getValue());
            }        

        }
       
        // REVISIT: synchronize?
        this.methods = methods;
    }
   
    public void callFunction( final String methodName, final List params, final Redirector redirector ) throws Exception {

        // REVISIT: subscribe to jci events and only update accordingly
        updateMethodIndex();

        Method m = (Method)methods.get(methodName);
        if (m == null) {
            throw new ProcessingException("no method '" + methodName + "' found in " + methods);
        }

        final CocoonContinuationContext context = createContinuationContext(params, redirector);

        Fiber f = new Fiber(new Invoker(m));

        final WebContinuation wk = continuationsMgr.createWebContinuation(
                f, null, timeToLive, getInterpreterID(), null);

        FlowHelper.setWebContinuation(
                ContextHelper.getObjectModel(avalonContext), wk);

        context.register();
        try {
            f.start();
        } finally {
            context.unregister();
        }
    }

    public void handleContinuation( final String id, final List params, final Redirector redirector ) throws Exception {

        final WebContinuation oldWebContinuation = continuationsMgr.lookupWebContinuation(
                id, getInterpreterID());

        if (oldWebContinuation == null) {
            throw new InvalidContinuationException("invalid continuation id " + id);
        }

        final CocoonContinuationContext context = createContinuationContext(params, redirector);

        Fiber f = (Fiber) oldWebContinuation.getContinuation();
        f = f.fork();   // create a new copy

        final WebContinuation newWebContinuation = continuationsMgr.createWebContinuation(
                f, oldWebContinuation, timeToLive, getInterpreterID(), null);

        FlowHelper.setWebContinuation(
                ContextHelper.getObjectModel(avalonContext), newWebContinuation);

        context.register();
        try {
            f._continue();
        } finally {
            context.unregister();
        }
    }
}

/*
 * 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;

import java.lang.reflect.Method;
import java.io.Serializable;

/**
 * A virtual "thread".
 *
 * <p>
 * A fiber to a thread is like a thread to a CPU.
 *
 * <p>
 * Fibers can emulate multiple independent execution flows on a single
 * (or possibly multiple) thread(s), just like threads emulate multple
 * independent execution flows on a single (or possibly multiple) CPU(s).
 *
 * <p>
 * The biggest difference between a fiber and a thread is in
 * its pre-emptiveness. Whereas a thread loses a CPU involuntarily (or
 * even without noticing), a fiber loses a thread only when it
 * {@link #yield() yields}.
 *
 * <p>
 * Another difference is that a fiber is fully implemented at Java level.
 * This allows you to stop a fiber and resume it later, execute it
 * on another thread, or even move it to another JVM, by using
 * serialization.
 *
 *
 *
 *
 *
 *
 * <h2>Usage</h2>
 * <p>
 * A fiber goes through the state transition much similar to that of {@link Thread}.
 * First, a {@link Fiber} gets created:
 *
 * <pre>
 * Fiber f = new Fiber(myRunnable);
 * </pre>
 *
 * <p>
 * Then it is started:
 *
 * <pre>
 * f.start();
 * </pre>
 *
 * <p>
 * At this point, a fiber is said to be {@link #isAlive() alive}.
 * The {@link Runnable#run()} method of <tt>myRunnable</tt> starts
 * executing by using the same thread. This execution continues until the fiber
 * yields or exits from the {@link Runnable#run()} method. When either of those
 * conditions are met, the thread used to run a fiber returns from the <tt>start</tt> method.
 *
 * <p>
 * The caller of the <tt>start</tt> method can then go on to do
 * some other things. Later, a fiber can be continued as follows:
 *
 * <pre>
 * f._continue();
 * </pre>
 *
 * <p>
 * At this point, a fiber resumes its execution from where it left off
 * before, again by using the same thread. Just like with
 * the <tt>start</tt> method, this execution continues until
 * the fiber yields or exits, and then the thread used to run a fiber
 * returns from the <tt>_continue</tt> method.
 *
 * <p>
 * Typically, the <tt>_continue</tt> method needs to be called repeatedly
 * for a fiber to complete its execution. Therefore, the simplest
 * execution loop would look like this:
 *
 * <pre>
 * while(f.isAlive())
 *     f._continue();
 * </pre>
 *
 *
 *
 *
 * <h2>Fiber Migration</h2>
 * <p>
 * A fiber is not tied to any particular thread. Therefore, it can be
 * started on one thread, then continued on another thread, and then
 * continued on yet another thread, and so on.
 *
 * This migration can happen while a fiber is not {@link #isExecuting() executing}.
 *
 * <p>
 * If all objects in a fiber's stack frames are {@link Serializable},
 * then a fiber can be serialized. This allows a fiber to be migrated
 * to another JVM. Note that for this to work correctly, all methods on
 * a fiber's stack frames must be exactly the same between two JVMs,
 * or else unpredictable behaviors will occur.
 *
 *
 * @author Kohsuke Kawaguchi
 */
public class Fiber implements Runnable, Continuable, Serializable, Cloneable {

    private /*final*/ Runnable target;

    private Continuation continuation;

    private boolean started = false;

    private boolean executing = false;

    /**
     * Creates a new {@link Fiber} that runs its {@link #run()} method
     * when started.
     */
    protected Fiber() {
        target = this;
    }

    /**
     * Creates a new {@link Fiber} that runs the {@link Runnable#run()} method
     * of the specified instance when started.
     */
    public Fiber(Runnable target) {
        this.target = target;
    }

    /**
     * Begins the execution of this fiber.
     *
     * <p>
     * Unlike normal thread, this method blocks until the fiber {@link #yield() yields}
     * or completes.
     *
     * @throws IllegalStateException
     *      if this fiber has already been started.
     */
    public void start() {
        if(started) {
            throw new IllegalStateException("the fiber is already started");
        }
        started = true;
        executing = true;
        try {
            continuation = Continuation.startWith("",new ContextImpl(this));
        } finally {
            executing = false;
        }
    }

    /**
     * Resumes the execution of this fiber.
     *
     * <p>
     * This is analogous to the thread resume operation. The fiber will pick up
     * execution from where it {@link #yield() yielded} last time.
     *
     * This method blocks until the fiber {@link #yield() yields} or completes.
     */
    public void _continue() {
        if(!isAlive()) {
            throw new IllegalStateException("the fiber has already completed");
        }
        if(executing) {
            throw new IllegalStateException("the fiber is already executing");
        }
        executing = true;
        try {
            continuation = Continuation.continueWith(continuation,new ContextImpl(this));
        } finally {
            executing = false;
        }
    }

    /**
     * Causes the currently runnning fiber to pause.
     *
     * This method stores the state of the execution on side and then
     * return from the {@link #start()} or {@link #_continue()} methods.
     *
     * @throws IllegalStateException
     *      unless this method is called from a fiber.
     */
    public static void yield() {
        Continuation.suspend();
    }

    /**
     * Creates an exact replica of this fiber.
     *
     * <p>
     * A fiber can be forked when it's not executing. If this fiber
     * has yielded at execution point A, then the newly created fiber
     * returned from this method will resume its execution from A.
     * In a way, this is similar to Unix process fork.
     *
     * <p>
     * objects on this fiber's stack frames aren't cloned, so two
     * fibers will refer to the same objects. Alternatively, serialization
     * can be also used to perform a deep-copy of a fiber.
     *
     * <p>
     * A fiber can be forked when it's not started yet, or when it's completed.
     *
     * @return
     *      always return a non-null valid {@link Fiber} object.
     *
     * @throws IllegalStateException
     *      if this fiber is executing.
     */
    public Fiber fork() {
        if(executing) {
            throw new IllegalStateException("cannot fork an executing fiber");
        }

        try {
            return (Fiber)clone();
        } catch (CloneNotSupportedException e) {
            // we implement Cloneable on Fiber, so this is impossible
            throw new Error(e);
        }
    }

    /**
     * Returns true if this fiber is still alive.
     *
     * A fiber is alive if it has been started but not yet died.
     * In particular, a fiber is alive even when it's not executing
     * on a thread.
     */
    public final boolean isAlive() {
        return continuation!=null;
    }

    /**
     * Returns true if this fiber is currently executing on a thread.
     */
    public final boolean isExecuting() {
        return executing;
    }

    /**
     * Should be overidden the derived classes to describe the code
     * that executes when the fiber runs.
     *
     * <p>
     * If this object is constructed with the {@link #Fiber(Runnable)} method,
     * it runs the <tt>run</tt> method of the specified <tt>Runnable</tt> object. Otherwise
     * report an error.
     */
    public void run() {
        if (target != null) {
            target.run();
       } else {
            throw new IllegalStateException(
                "This is most likely a mistake. You should either specify a Runnable object " +
                "as a constructor parameter, or you should override the run method.");
        }
    }

    /**
     * Gets the currently executing fiber.
     *
     * <p>
     * This method works like {@link Thread#currentThread()}.
     *
     * @return
     *      null if no fiber is executing (IOW, if this method is called from outside
     *      a fiber.) Otherwise non-null valid fiber.
     */
    public static Fiber currentFiber() {
        ContinuationContext context = Continuation.currentContinuation().getContext();
        if(!(context instanceof ContextImpl)) {
            throw new IllegalStateException("no fiber is executing");
        }
        Fiber f = ((ContextImpl)context).fiber;
        if(!f.isExecuting())
            throw new Error("a bug in javaflow");
        return f;
    }


    private static final class ContextImpl extends ContinuationContext implements MethodLookup {
        Fiber fiber;
        public ContextImpl(Fiber thread) {
            this.fiber = thread;
            setMethodLookup(this);
        }

        public Method getMethod(String method) {
            try {
                return Invoker.class.getDeclaredMethod("run",EMPTY_CLASSES);
            } catch (NoSuchMethodException e) {
                throw new Error(e); // impossible
            }
        }
        private static final Class[] EMPTY_CLASSES = new Class[0];
    }

    static final class Invoker implements ContinuationCapable, Serializable {
        /**
         * Called by {@link Continuation} and forwards the invocation to the thread.
         * We can't have {@link Continuation} call the thread.run() method directly
         * because we don't know if the thread object has no-arg constructor.
         *
         * This method is continuation capable without the byte code enhancements.
         */
        /*package*/ void run() { // so that it can be called from Continuation
            ContextImpl context = (ContextImpl)Continuation.currentContinuation().getContext();
            context.fiber.run();
        }
        private static final long serialVersionUID = 1L;
    }

    private static final long serialVersionUID = 1L;
}

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Torsten Curdt
>> See the example in my blog ...which is actually

>> taken from the Cocoon integration. (I think in
>> there is also the link to the class) Would be
>> great if you could also have a look into that
>> class.
>>
>
> I looked at Cocoon code you had in [1]. I didn't particularly see  
> anything that made me rethink (IOW, I don't see anything that  
> absolutely requires MethodLookup nor ContinuationContext instead of  
> Runnable.)
Had a look into your implementation
...you have the "run" method delegating to
the different methods.

If you want to get rid of the of the method
lookup you do need to pass in the Runnable
also to the continueWith ...not sure if I
like that.

I had similar idea in the beginning:

  startWith(Method, ContinuationContext)
  continueWith(Method, Continuation, ContinuationContext)

What I did not like: Passing in of the
Continuation already implies the Method.

Beforehand the method was saved inside
the Continuation object. But this does
not work when it comes down to serialization.

BTW: IIRC I needed to mark the static as
transient for the XStream serialization
...but not totally sure.

> But at the same time, I saw that you have some existing investments  
> with the current javaflow Continuation API and it's very  
> understandable that you don't want it to change.

Well ...it's still marked alpha so as long
as it makes sense to me I am fine changing
it.

But TBH I currently would like to focus on
the current bytecode rewriting stuff first
before changing the API that much.

> I see the desire to pass some contextual information to the invoked  
> method, but that is a fairly common requirement even if you aren't  
> using javaflow at all. javaflow just keeps it and stores it  
> somewhere for later retrieval, which can be better done by the code  
> that knows what the scope of a given context object is (like  
> ThreadLocal, singleton, HttpSession, etc.)
>
>
> Just to make sure that I'm not missing something, I rewrote the  
> JavaInterpreter and CocoonContinuationContext by using the  
> ContinuationThread class (which I renamed to Fiber) instead of the  
> current Continuation API. The only difference is that you now do:
>
> CocoonContinuationContext.getCurrent()
>
> instead of:
>
> (CocoonContinuationContext)Continuation.currentContinuation
> ().getContext()
Hm... it's shorter but I don't like it.
It's not obvious where the context comes
from.

I would -1 that one.

> See the attachments for the exact code. All in all, I didn't think  
> this re-write is ugly, but that is always a subjective issue.

I don't understand this forking and cloning
stuff - you don't need that. A continuation
should be re-entrant and always create a new
one as a result.

> Anyway, I'm no longer too keen about convincing you to change the  
> API of the Continuation class. If you like my rewrite, that's good,  
> but if not, that's also fine with me. The current Continuation API  
> makes the Fiber class implementation uglier, but that's not too big  
> a problem.
>
> Instead, I'm hoping that you allow me to commit this Fiber class to  
> javaflow, as this is what I primarily want to use in my code.

If you don't mind I would prefer if you keep
that code in your codebase for now. Let's get
back to that once we have the rewriting based
on ASM in place. I would like to focus on the
hard part first ;)

Would that be ok for you?

cheers
--
Torsten

PGP.sig (193 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi
(Please check the other e-mail I sent, which is hopefully much less
controversial.)

Torsten Curdt wrote:

>>> See the example in my blog ...which is actually
>>> taken from the Cocoon integration. (I think in
>>> there is also the link to the class) Would be
>>> great if you could also have a look into that
>>> class.
>>>
>>
>> I looked at Cocoon code you had in [1]. I didn't particularly see  
>> anything that made me rethink (IOW, I don't see anything that  
>> absolutely requires MethodLookup nor ContinuationContext instead of  
>> Runnable.)
>
> Had a look into your implementation
> ..you have the "run" method delegating to
> the different methods.

The Invoker class was needed to work around the problem/feature in the
current Continuation API that the first object to be invoked needs to
have a default constructor. The Fiber class can be extended by users and
therefore it may not have the default constructor, so I can't just call
Fiber.run immediately from Continuation.execute().

Fiber.run delegates to another Runnable because that's what
java.lang.Thread does.


> If you want to get rid of the of the method
> lookup you do need to pass in the Runnable
> also to the continueWith ...not sure if I
> like that.

No, I don't think you have to. That Runnable object is a part of
Continuation already. The continueWith method can look it up from there.
Specifically, it already retains a reference to that object in Stack. We
just need to make it explicitly accessible (instead of fiddling with
references in stacks to get to it.)


> I had similar idea in the beginning:
>
>   startWith(Method, ContinuationContext)
>   continueWith(Method, Continuation, ContinuationContext)
>
> What I did not like: Passing in of the
> Continuation already implies the Method.

I agree. That's why I originally suggested to use Runnable in this
level, to get rid of Method altogether.

> Beforehand the method was saved inside
> the Continuation object. But this does
> not work when it comes down to serialization.

By calling Runnable.run() method, you no longer have to save the Method
object in Continuation. That means no MethodLookup is necessary, no
method name is necessary.

> BTW: IIRC I needed to mark the static as
> transient for the XStream serialization
> ..but not totally sure.

I used XStream in other projects, and I believe it didn't persist static
fields. But I will put that back. Maybe we are using different versions.

>> But at the same time, I saw that you have some existing investments  
>> with the current javaflow Continuation API and it's very  
>> understandable that you don't want it to change.
>
> Well ...it's still marked alpha so as long
> as it makes sense to me I am fine changing
> it.
>
> But TBH I currently would like to focus on
> the current bytecode rewriting stuff first
> before changing the API that much.

OK.



>> See the attachments for the exact code. All in all, I didn't think  
>> this re-write is ugly, but that is always a subjective issue.
>
> I don't understand this forking and cloning
> stuff - you don't need that. A continuation
> should be re-entrant and always create a new
> one as a result.

Unlike Continuation, Fiber is a mutable object. It updates itself as you
continue execution. That's why sometimes you want a "fork" to create an
identical copy.

Fiber.fork doesn't deep-copy Continuation, as Continuation itself
doesn't need to be copied. It's just Fiber object that needs to be
copied, hence the use of clone().



>> Anyway, I'm no longer too keen about convincing you to change the  
>> API of the Continuation class. If you like my rewrite, that's good,  
>> but if not, that's also fine with me. The current Continuation API  
>> makes the Fiber class implementation uglier, but that's not too big  
>> a problem.
>>
>> Instead, I'm hoping that you allow me to commit this Fiber class to  
>> javaflow, as this is what I primarily want to use in my code.
>
> If you don't mind I would prefer if you keep
> that code in your codebase for now. Let's get
> back to that once we have the rewriting based
> on ASM in place. I would like to focus on the
> hard part first ;)
 >
 > Would that be ok for you?

Hmm...

Even if Fiber doesn't change any of the existing Continuation class, do
you still feel uncomfortable with it?

As an user, it doesn't really matter to me what byte-code manipulation
library javaflow is using, because it's completely behind the scene. The
current BCEL one seems to be working, so it's not very high priority for
me to rewrite javaflow by using ASM. Besides, I doubt if I can be of any
help when it comes to porting javaflow from BCEL to ASM. That part is
the guts of javaflow and it takes you to change it.

For me, the javaflow API surface is of a higher priority, because in the
end my goal is to use it. I suspect that a thread-like API connects to
users more easily, as there's less learning involved. I'm hoping that
this contributes to an improved user experience. For this reason, I hope
it's beneficial to the javaflow project.

Once again, I'm not trying to convince you to change the existing
Continuation class in any substantial way. I'm only asking you to put
this Fiber class side-by-side with the current Continuation class.

Please please can I have this class? I promise I won't talk about the
Continuation class signature change any more :-)

If not, I guess I just need to accumulate more small improvements to
make you feel comfortable with me. It's disappointing for me for now,
but that's certainly fair, I guess.

--
Kohsuke Kawaguchi

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Torsten Curdt

>> If you want to get rid of the of the method
>> lookup you do need to pass in the Runnable
>> also to the continueWith ...not sure if I
>> like that.
>>
>
> No, I don't think you have to. That Runnable object is a part of  
> Continuation already. The continueWith method can look it up from  
> there. Specifically, it already retains a reference to that object  
> in Stack. We just need to make it explicitly accessible (instead of  
> fiddling with references in stacks to get to it.)
I *do* think you have to :)

...think about the serialization. The continuation
has been restored. THERE IS NO REFERENCE TO A METHOD
OR RUNNABLE. Please check with the current implementation.
For debugging you can add logging to see what's been put
onto the stack.

>> I had similar idea in the beginning:
>>   startWith(Method, ContinuationContext)
>>   continueWith(Method, Continuation, ContinuationContext)
>> What I did not like: Passing in of the
>> Continuation already implies the Method.
>>
>
> I agree. That's why I originally suggested to use Runnable in this  
> level, to get rid of Method altogether.

Well ...that's not the point. I really do
think you have to pass in the Runnable or
Method to "continueWith" ...if you don't have
a lookup. That's why I don't like this either:

  startWith(Runnable, ContinuationContext)
  continueWith(Runnable, Continuation, ContinuationContext)

>> Beforehand the method was saved inside
>> the Continuation object. But this does
>> not work when it comes down to serialization.
>>
>
> By calling Runnable.run() method, you no longer have to save the  
> Method object in Continuation. That means no MethodLookup is  
> necessary, no method name is necessary.

...does not matter whether we are talking about
Method or Runnable. If you want to get rid of
passing in the parameter you have to store it
somewhere inside the continuation - which is
not ok for the serialization.

>> BTW: IIRC I needed to mark the static as
>> transient for the XStream serialization
>> ..but not totally sure.
>>
>
> I used XStream in other projects, and I believe it didn't persist  
> static fields. But I will put that back. Maybe we are using  
> different versions.

Maybe just give the serialization testcase
a try and turn it on/off based on that result.

>>> See the attachments for the exact code. All in all, I didn't  
>>> think  this re-write is ugly, but that is always a subjective issue.
>>>
>> I don't understand this forking and cloning
>> stuff - you don't need that. A continuation
>> should be re-entrant and always create a new
>> one as a result.
>>
>
> Unlike Continuation, Fiber is a mutable object. It updates itself  
> as you continue execution. That's why sometimes you want a "fork"  
> to create an identical copy.
...that also means for persistence you would
have to serialize the Fiber object, too. Hmm...

> Fiber.fork doesn't deep-copy Continuation, as Continuation itself  
> doesn't need to be copied. It's just Fiber object that needs to be  
> copied, hence the use of clone().

Hmmm... why do you need a mutable object at all?

>> If you don't mind I would prefer if you keep
>> that code in your codebase for now. Let's get
>> back to that once we have the rewriting based
>> on ASM in place. I would like to focus on the
>> hard part first ;)
>>
> >
> > Would that be ok for you?
>
> Hmm...
>
> Even if Fiber doesn't change any of the existing Continuation  
> class, do you still feel uncomfortable with it?
>
Well ...point is - it's a second API.

> As an user, it doesn't really matter to me what byte-code  
> manipulation library javaflow is using, because it's completely  
> behind the scene.

Sure ...but don't you think it's more important
the guts are working properly before abstracting
the further abstracting the API?

> The current BCEL one seems to be working, so it's not very high  
> priority for me to rewrite javaflow by using ASM. Besides, I doubt  
> if I can be of any help when it comes to porting javaflow from BCEL  
> to ASM. That part is the guts of javaflow and it takes you to  
> change it.

...too bad - hoped you could help me there as well :)

> For me, the javaflow API surface is of a higher priority, because  
> in the end my goal is to use it. I suspect that a thread-like API  
> connects to users more easily, as there's less learning involved.  
> I'm hoping that this contributes to an improved user experience.  
> For this reason, I hope it's beneficial to the javaflow project.

It does lower the barrier ...but I am not sure
whether it really helps people to understand
the concept behind it. It might even blur
that a bit.

> Once again, I'm not trying to convince you to change the existing  
> Continuation class in any substantial way. I'm only asking you to  
> put this Fiber class side-by-side with the current Continuation class.
>
> Please please can I have this class? I promise I won't talk about  
> the Continuation class signature change any more :-)

LOL :o)

Comeon ...it's not big difference whether it's
in your codebase or inside the javaflow codebase,
isn't it?

...I am not saying "no" but "convince me" ;)

> If not, I guess I just need to accumulate more small improvements  
> to make you feel comfortable with me. It's disappointing for me for  
> now, but that's certainly fair, I guess.

Sorry, don't want to come across to negative
or protective. I just don't feel too good
having two APIs in the first release already.

cheers
--
Torsten

PGP.sig (193 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi
Torsten Curdt wrote:

>>> If you want to get rid of the of the method
>>> lookup you do need to pass in the Runnable
>>> also to the continueWith ...not sure if I
>>> like that.
>>>
>>
>> No, I don't think you have to. That Runnable object is a part of  
>> Continuation already. The continueWith method can look it up from  
>> there. Specifically, it already retains a reference to that object  
>> in Stack. We just need to make it explicitly accessible (instead of  
>> fiddling with references in stacks to get to it.)
>
> I *do* think you have to :)
>
> ..think about the serialization. The continuation
> has been restored. THERE IS NO REFERENCE TO A METHOD
> OR RUNNABLE. Please check with the current implementation.
> For debugging you can add logging to see what's been put
> onto the stack.
Here's my reasoning. Please tell me where I made a mistake. Let's take
the serialization test case as an example.

Suppose Calculator implements a Runnable and its run method is the entry
point. We run Calculator and it suspends. We start the stack capturing,
and when a new continuation object is returned, it contains this
runnable object. You can see this in the output from XStream that I
attached.

In particular, because the Runnable object invoked is always the very
bottom of the stack trace, you can always access it at a top of the
rstack. You are throwing it away right now, but you just need to keep it
little longer. The object is also on the ostack, although this is less
accessible (because it's not always on top.)

When you serialize a Continuation, therefore, the Runnable object also
gets serialized. You deserialize it back, you get the Runnable object back.

So when you hit Continuation.continueWith with a deserialized
Continuation object, all you need to do is just to access the top of the
rstack to get the Runnable object back, then invoke its run method.


> Well ...that's not the point. I really do
> think you have to pass in the Runnable or
> Method to "continueWith" ...if you don't have
> a lookup. That's why I don't like this either:
>
>   startWith(Runnable, ContinuationContext)
>   continueWith(Runnable, Continuation, ContinuationContext)

I hope the above argument convinced you that you don't have to pass in
Runnable to the continueWith method.


Or let's put this in another way. If I can successfully change the
Continuation API to:

    startWith(Runnable, ContinuationContext)
    continueWith(Continuation, ContinuationContext)

and make the serialization test work, would you be willing to accept the
changes? The quickest way to find out if this is doable or not is to
actually do it.



>> Unlike Continuation, Fiber is a mutable object. It updates itself  
>> as you continue execution. That's why sometimes you want a "fork"  
>> to create an identical copy.
>
> ..that also means for persistence you would
> have to serialize the Fiber object, too. Hmm...

Yes, if you choose to use a fiber, yes.

>> Fiber.fork doesn't deep-copy Continuation, as Continuation itself  
>> doesn't need to be copied. It's just Fiber object that needs to be  
>> copied, hence the use of clone().
>
> Hmmm... why do you need a mutable object at all?

It's not that I want a mutable object. It's convenient to have a
representation for a "thread" of execution, and such representation is
going to be mutable because execution state changes as it runs.

Use in Cocoon is special in the sense that it keeps the continuation
object at every yield point. Neither a workflow engine nor an agent
container does this.


> Sure ...but don't you think it's more important
> the guts are working properly before abstracting
> the further abstracting the API?

If it's not working properly, yes. I just assumed that it is working
(besides the monitor issue.) Is there any other known problems?

>> The current BCEL one seems to be working, so it's not very high  
>> priority for me to rewrite javaflow by using ASM. Besides, I doubt  
>> if I can be of any help when it comes to porting javaflow from BCEL  
>> to ASM. That part is the guts of javaflow and it takes you to  
>> change it.
>
> ..too bad - hoped you could help me there as well :)

I saw that the instrumentation algorithm can be probably optimized (for
example, no need to instrument StringBuffer.append() operation, share
the stack capturing code, etc) Now that I actually saw the decompiled
byte code, I'm more willing to change it than before.


> Comeon ...it's not big difference whether it's
> in your codebase or inside the javaflow codebase,
> isn't it?
>
> ..I am not saying "no" but "convince me" ;)

It's not a big difference, in a way, yes. But on the other hand, if none
of the changes that I really care is accepted, it's very difficult for
me to help.

I need your help to find the middle place we can meet. I suggested to
get rid of MethodLookup in favor of Runnable, and you didn't like it. So
I suggested to keep it as is and add what I wanted as another class, and
you didn't like it either.

I spent time rewriting the Cocoon portion just to show you how it can be
reasonably done. I think I gave a reasonable set of justifications for
each proposal, like simplicity, ease of use, etc.

What do you need to be convinced of? That this is doable? Or that this
is beneficial? Or is it something else?


--
Kohsuke Kawaguchi

<org.apache.commons.javaflow.Continuation>
  <methodName>main</methodName>
  <stack>
    <istack>
      <int>1</int>
      <int>18</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
      <int>0</int>
    </istack>
    <fstack>
      <float>0.0</float>
      <float>0.0</float>
      <float>0.0</float>
      <float>0.0</float>
      <float>0.0</float>
    </fstack>
    <dstack>
      <double>0.0</double>
      <double>0.0</double>
      <double>0.0</double>
      <double>0.0</double>
      <double>0.0</double>
    </dstack>
    <lstack>
      <long>0</long>
      <long>0</long>
      <long>0</long>
      <long>0</long>
      <long>0</long>
    </lstack>
    <ostack>
      <org.apache.commons.javaflow.testcode.Calculator>
        <field>6</field>
      </org.apache.commons.javaflow.testcode.Calculator>
      <org.apache.commons.javaflow.testcode.SomeReference/>
      <null/>
      <null/>
      <null/>
      <null/>
      <null/>
      <null/>
      <null/>
      <null/>
    </ostack>
    <rstack>
      <org.apache.commons.javaflow.testcode.Calculator reference="../../ostack/org.apache.commons.javaflow.testcode.Calculator"/>
      <null/>
      <null/>
      <null/>
      <null/>
    </rstack>
    <iTop>2</iTop>
    <fTop>0</fTop>
    <dTop>0</dTop>
    <lTop>0</lTop>
    <oTop>2</oTop>
    <rTop>0</rTop>
  </stack>
  <root reference=".."/>
</org.apache.commons.javaflow.Continuation>

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Torsten Curdt

>>> Fiber.fork doesn't deep-copy Continuation, as Continuation  
>>> itself  doesn't need to be copied. It's just Fiber object that  
>>> needs to be  copied, hence the use of clone().
>>>
>> Hmmm... why do you need a mutable object at all?
>>
>
> It's not that I want a mutable object. It's convenient to have a  
> representation for a "thread" of execution, and such representation  
> is going to be mutable because execution state changes as it runs.
>
> Use in Cocoon is special in the sense that it keeps the  
> continuation object at every yield point. Neither a workflow engine  
> nor an agent container does this.
This a very good point! Granted!

>> Sure ...but don't you think it's more important
>> the guts are working properly before abstracting
>> the further abstracting the API?
>>
>
> If it's not working properly, yes. I just assumed that it is  
> working (besides the monitor issue.) Is there any other known  
> problems?

The following problems are still on the TODO list

  o try/catch/finally
  o synchronized

plus the code just asks for a cleanup and improvements.
...and I wanted to do that while porting to ASM.

> I saw that the instrumentation algorithm can be probably optimized  
> (for example, no need to instrument StringBuffer.append()  
> operation, share the stack capturing code, etc) Now that I actually  
> saw the decompiled byte code, I'm more willing to change it than  
> before.

Hehe :) ..see?

>> Comeon ...it's not big difference whether it's
>> in your codebase or inside the javaflow codebase,
>> isn't it?
>> ..I am not saying "no" but "convince me" ;)
>>
>
> It's not a big difference, in a way, yes. But on the other hand, if  
> none of the changes that I really care is accepted, it's very  
> difficult for me to help.
>
> I need your help to find the middle place we can meet. I suggested  
> to get rid of MethodLookup in favor of Runnable, and you didn't  
> like it. So I suggested to keep it as is and add what I wanted as  
> another class, and you didn't like it either.
>
> I spent time rewriting the Cocoon portion just to show you how it  
> can be reasonably done. I think I gave a reasonable set of  
> justifications for each proposal, like simplicity, ease of use, etc.
>
> What do you need to be convinced of? That this is doable? Or that  
> this is beneficial? Or is it something else?
TBH ...I admit I've missed that we can use the
instance from the stack. So you got a real good point!

So you convinced me to go ahead with the Runnable
approach. But still I am not to eager to have that
Fiber class in the codebase ...at least for now.

Can you live with that for the moment?

cheers
--
Torsten

PGP.sig (193 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [javaflow] MethodLookup

Kohsuke Kawaguchi-2
Torsten Curdt wrote:
> The following problems are still on the TODO list
>
>   o try/catch/finally
>   o synchronized
>
> plus the code just asks for a cleanup and improvements.
> ..and I wanted to do that while porting to ASM.

You mean, you'd like those clean ups and etc done to both the BCEL
version and the ASM version?


>> I saw that the instrumentation algorithm can be probably optimized  
>> (for example, no need to instrument StringBuffer.append()  
>> operation, share the stack capturing code, etc) Now that I actually  
>> saw the decompiled byte code, I'm more willing to change it than  
>> before.
>
> Hehe :) ..see?

You got me there. I think I'll study the code more closely.
I started to develop a few ideas, but I'm wondering if I should hold
those off until the ASM port to complete.


> TBH ...I admit I've missed that we can use the
> instance from the stack. So you got a real good point!
>
> So you convinced me to go ahead with the Runnable
> approach. But still I am not to eager to have that
> Fiber class in the codebase ...at least for now.
>
> Can you live with that for the moment?

Yes, yes, yes! I really appreciate you let me do this.

--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

smime.p7s (4K) Download Attachment