changeset 143:568ebe7237f1

new continuation patch
author Hiroshi Yamauchi <yamauchi@google.com>
date Thu, 28 Oct 2010 15:14:50 +0200
parents 4c80d5b4cbff
children 3d915c8e9b23
files callcc.patch callcc_old.patch continuation.patch series
diffstat 4 files changed, 2648 insertions(+), 1331 deletions(-) [+]
line wrap: on
line diff
--- a/callcc.patch	Wed Sep 29 15:47:58 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1330 +0,0 @@
-diff --git a/src/share/classes/javax/stack/CoRunnable.java b/src/share/classes/javax/stack/CoRunnable.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/CoRunnable.java
-@@ -0,0 +1,4 @@
-+package javax.stack;
-+public interface CoRunnable {
-+	public Object run();
-+}
-\ No newline at end of file
-diff --git a/src/share/classes/javax/stack/Continuable.java b/src/share/classes/javax/stack/Continuable.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/Continuable.java
-@@ -0,0 +1,32 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+import java.lang.annotation.*;
-+
-+@Documented
-+@Retention(RetentionPolicy.RUNTIME)
-+@Target(ElementType.METHOD)
-+public @interface Continuable {
-+	ContinuableAccess value() default ContinuableAccess.HIDDEN;
-+}
-diff --git a/src/share/classes/javax/stack/ContinuableAccess.java b/src/share/classes/javax/stack/ContinuableAccess.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/ContinuableAccess.java
-@@ -0,0 +1,27 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+public enum ContinuableAccess {
-+		HIDDEN, READONLY, READWRITE
-+}
-diff --git a/src/share/classes/javax/stack/Continuation.java b/src/share/classes/javax/stack/Continuation.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/Continuation.java
-@@ -0,0 +1,115 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+/**
-+ * @author lukas.stadler@jku.at
-+ */
-+@SuppressWarnings("unused")
-+public class Continuation {
-+	private static class CONTINUATION_CAPTURED {
-+	}
-+
-+	public static final Object CAPTURED = CONTINUATION_CAPTURED.class;
-+	private Object data;
-+	private Thread thread;
-+
-+	private static native void registerNatives();
-+
-+	static {
-+		registerNatives();
-+	}
-+
-+	/**
-+	 * Saves the current thread state into the continuation object
-+	 * @return null if the continuation was saved or the value given to resume if it was resumed
-+	 */
-+	public final native Object save();
-+
-+	/**
-+	 * Restores the stack to the state that it had when the continuation was saved.
-+	 * @param retValue the value that the save method should return
-+	 */
-+	public final native void resume(Object retValue);
-+
-+	/**
-+	 * Yields to the given target continuation, passing along the current continuation
-+	 * @param target the continuation that will be reinstated
-+	 */
-+	@Continuable
-+	public static final void yield(Continuation target) {
-+		Continuation c = new Continuation();
-+		if (c.save() == null)
-+			target.resume(c);
-+	}
-+
-+	/*
-+	 * This method will be called by startDelimited
-+	 */
-+	@Continuable
-+	private static final Object startDelimitedInternal(DelimitedRunnable runnable, Object firstValue) {
-+		Continuation cont = new Continuation();
-+		Object ret = cont.save();
-+		if (ret == CAPTURED)
-+			runnable.run(cont, firstValue);
-+		return ret;
-+	}
-+
-+	public static final native Object startDelimited(DelimitedRunnable runnable, Object firstValue);
-+
-+	/*
-+	 * This method will be called by continueDelimited
-+	 */
-+	@Continuable
-+	private static final Object continueDelimitedInternal(Continuation cont, Object value) {
-+		cont.resume(value);
-+		return null;
-+	}
-+
-+	public static final native Object continueDelimited(Continuation continuation, Object value);
-+
-+	public final native Object dump();
-+
-+	private static final native Object storeFrameObject(Object retValue);
-+
-+	private static final native void storeFrameVoid();
-+
-+	private static final native boolean storeFrameBoolean(boolean retValue);
-+
-+	private static final native byte storeFrameByte(byte retValue);
-+
-+	private static final native char storeFrameChar(char retValue);
-+
-+	private static final native short storeFrameShort(short retValue);
-+
-+	private static final native int storeFrameInt(int retValue);
-+
-+	private static final native long storeFrameLong(long retValue);
-+
-+	private static final native float storeFrameFloat(float retValue);
-+
-+	private static final native double storeFrameDouble(double retValue);
-+
-+	private static final native Throwable unwind(Throwable e);
-+
-+}
-diff --git a/src/share/classes/javax/stack/ContinuationPermission.java b/src/share/classes/javax/stack/ContinuationPermission.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/ContinuationPermission.java
-@@ -0,0 +1,34 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+import java.security.BasicPermission;
-+
-+/* name is either "resumeSecure" or "resumeUnsecure" */
-+public class ContinuationPermission extends BasicPermission {
-+	private static final long serialVersionUID = -3608714945512368738L;
-+
-+	public ContinuationPermission(String name) {
-+		super(name);
-+	}
-+}
-\ No newline at end of file
-diff --git a/src/share/classes/javax/stack/Coroutine.java b/src/share/classes/javax/stack/Coroutine.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/Coroutine.java
-@@ -0,0 +1,305 @@
-+package javax.stack;
-+import javax.stack.Continuable;
-+import javax.stack.Continuation;
-+
-+/**
-+ * Experimental coroutine implementation using the continuation framework.
-+ * 
-+ * This class works very much like the {@link Thread} class, it can either be supplied with a {@link CoRunnable} upon creation or
-+ * the run method can be overridden.<br/>
-+ * All coroutines belonging to a context are kept in a doubly-linked ring data structure. Due to this there is an ordering of
-+ * coroutines, and the next and previous coroutines are known.
-+ * 
-+ * @author lukas.stadler@jku.at
-+ */
-+public class Coroutine {
-+	// exception used to terminate/close coroutines, created only once because exception creation is expensive
-+	private static final CoroutineExitException exitException = new CoroutineExitException();
-+
-+	// contains the actual stack frames, local variables, etc.
-+	private Continuation data;
-+
-+	// the context this coroutine belongs to
-+	private CoroutineContext context;
-+
-+	// the code that will be executed if run isn't overridden
-+	private CoRunnable runnable;
-+
-+	// the pointers for the doubly-linked ring data structure
-+	private Coroutine last;
-+	private Coroutine next;
-+
-+	// if this is non-null then an exception will be raised when this coroutine is resumed
-+	private RuntimeException exception;
-+
-+	/**
-+	 * Creates a new coroutine that belongs to the currently active {@link CoroutineContext}. This constructor is only useful if
-+	 * the run method is overridden. The coroutine will be inserted after the current coroutine of the context, or as the first
-+	 * coroutine if it is the first one added to the context.
-+	 * @throws IllegalThreadStateException if there is no current context
-+	 */
-+	public Coroutine() {
-+		initialize(CoroutineContext.getCurrent());
-+	}
-+
-+	/**
-+	 * Creates a new coroutine that belongs to the currently active {@link CoroutineContext}. The coroutine will execute the given
-+	 * CoRunnable (if it is non-null). The coroutine will be inserted after the current coroutine of the context, or as the first
-+	 * coroutine if it is the first one added to the context.
-+	 * @throws IllegalThreadStateException if there is no current context
-+	 */
-+	public Coroutine(CoRunnable runnable) {
-+		this.runnable = runnable;
-+		initialize(CoroutineContext.getCurrent());
-+	}
-+
-+	/**
-+	 * Creates a new coroutine that belongs to the given {@link CoroutineContext}. This constructor is only useful if the run
-+	 * method is overridden. The coroutine will be inserted after the current coroutine of the context, or as the first coroutine
-+	 * if it is the first one added to the context.
-+	 * @throws IllegalArgumentException if context is null
-+	 */
-+	public Coroutine(CoroutineContext context) {
-+		if (context == null)
-+			throw new IllegalArgumentException("context cannot be null");
-+		initialize(context);
-+	}
-+
-+	/**
-+	 * Creates a new coroutine that belongs to the given {@link CoroutineContext}. The coroutine will execute the given CoRunnable
-+	 * (if it is non-null). The coroutine will be inserted after the current coroutine of the context, or as the first coroutine
-+	 * if it is the first one added to the context.
-+	 * @throws IllegalArgumentException if context is null
-+	 */
-+	public Coroutine(CoroutineContext context, CoRunnable runnable) {
-+		if (context == null)
-+			throw new IllegalArgumentException("context cannot be null");
-+		this.runnable = runnable;
-+		initialize(context);
-+	}
-+
-+	/*
-+	 * Adds this coroutine into the doubly-linked ring of the given context.
-+	 */
-+	private void initialize(CoroutineContext context) {
-+		if (context == null)
-+			throw new IllegalThreadStateException("Cannot create Coroutine without CoroutineContext");
-+		context.coroutineAdded(this);
-+		this.context = context;
-+		if (context.getCurrentCoroutine() == null) {
-+			last = this;
-+			next = this;
-+			context.setCurrentCoroutine(this);
-+		}
-+		else {
-+			Coroutine current = context.getCurrentCoroutine();
-+			last = current.last;
-+			next = current;
-+			current.last = this;
-+			last.next = this;
-+		}
-+	}
-+
-+	/**
-+	 * Yields to the target coroutine, without changing the order of the coroutines
-+	 * @param target the coroutine that will be current after this call
-+	 * @param value the value that is passed to the target coroutine
-+	 * @return the value passed to the yield that makes this coroutine active again
-+	 */
-+	@Continuable
-+	private Object yieldToInternal(Coroutine target, Object value) {
-+		assert target != null;
-+		// System.out.println("yield to " + target + ", value="+value);
-+		context.setCurrentCoroutine(target);
-+		if (data == null)
-+			data = new Continuation();
-+		Object ret = data.save();
-+		try {
-+			// System.out.println("ret="+ret);
-+			if (ret == Continuation.CAPTURED) {
-+				if (target.data == null)
-+					context.startCoroutine.resume(value);
-+				else {
-+					// System.out.println("target resume");
-+					target.data.resume(value);
-+				}
-+				return null;
-+			}
-+			else
-+				return ret;
-+		}
-+		finally {
-+			if (exception != null) {
-+				// System.out.println("throwing exception in coroutine " + this + ": " + exception);
-+				throw exception;
-+			}
-+		}
-+	}
-+
-+	/**
-+	 * Closes the coroutine. This will resume the coroutine and throw a {@link CoroutineExitException}. If it propagates down to
-+	 * the starting method the coroutine will end. Thus coroutines can veto the close operation if they catch the
-+	 * CoroutineExitException.
-+	 */
-+	@Continuable
-+	public final void close() {
-+		if (isActive()) {
-+			exception = exitException;
-+			if (context == CoroutineContext.getCurrent()) {
-+				if (this == Coroutine.getCurrent())
-+					throw exception;
-+				else
-+					try {
-+						yieldTo(this, null);
-+					}
-+					catch (CoroutineExitException e) {
-+						// ignore
-+					}
-+			}
-+		}
-+	}
-+
-+	/**
-+	 * @return the currently active coroutine, or null if there is no current coroutine context
-+	 */
-+	public static Coroutine getCurrent() {
-+		CoroutineContext currentContext = CoroutineContext.getCurrent();
-+		return currentContext == null ? null : currentContext.getCurrentCoroutine();
-+	}
-+
-+	/**
-+	 * @return true if this coroutine hasn't ended yet
-+	 */
-+	public final boolean isActive() {
-+		assert (next != null) == (last != null);
-+		return next != null;
-+	}
-+
-+	/**
-+	 * @return the coroutine that is scheduled to be executed after this one
-+	 */
-+	public final Coroutine getNext() {
-+		return next;
-+	}
-+
-+	/**
-+	 * @return the coroutine that was executed before this one
-+	 */
-+	public final Coroutine getLast() {
-+		return last;
-+	}
-+
-+	/**
-+	 * @return the context this coroutine belongs to
-+	 */
-+	public final CoroutineContext getContext() {
-+		return context;
-+	}
-+
-+	/**
-+	 * Yields to the next scheduled coroutine (as determined by the scheduling behavior of the coroutine context)
-+	 * @param value the value to be passed to the next coroutine
-+	 * @return the value passed to this coroutine when it is resumed
-+	 */
-+	@Continuable
-+	public static Object yield(Object value) {
-+		Coroutine current = getCurrent();
-+		return yieldTo(current.context.scheduleNext(current), value);
-+	}
-+
-+	/**
-+	 * Yields to the last coroutine. This can be used to implement coroutines that generate values for a caller.
-+	 * @param value the value to be passed to the next coroutine
-+	 * @return the value passed to this coroutine when it is resumed
-+	 */
-+	@Continuable
-+	public static Object yieldReturn(Object value) {
-+		Coroutine current = getCurrent();
-+		// System.out.println("current=" + current);
-+		// System.out.println("last=" + current.last);
-+		return current.yieldToInternal(current.last, value);
-+	}
-+
-+	/**
-+	 * Yields to the next coroutine (ignoring the scheduling behavior of the coroutine context). This does not change the
-+	 * coroutine order.
-+	 * @param value the value to be passed to the next coroutine
-+	 * @return the value passed to this coroutine when it is resumed
-+	 */
-+	@Continuable
-+	public static Object yieldNext(Object value) {
-+		Coroutine current = getCurrent();
-+		return current.yieldToInternal(current.next, value);
-+	}
-+
-+	/**
-+	 * Yields to the given coroutine (ignoring the scheduling behavior of the coroutine context). The coroutine order will be
-+	 * changed so that the given coroutine is the next one.
-+	 * @param target the coroutine to be executed next
-+	 * @param value the value to be passed to the next coroutine
-+	 * @return the value passed to this coroutine when it is resumed
-+	 */
-+	@Continuable
-+	public static Object yieldTo(Coroutine target, Object value) {
-+		Coroutine current = getCurrent();
-+		if (target != current.next) {
-+			// remove target from its current position
-+			target.last.next = target.next;
-+			target.next.last = target.last;
-+			// add target at the current position
-+			target.last = current;
-+			target.next = current.next;
-+			target.last.next = target;
-+			target.next.last = target;
-+		}
-+		return current.yieldToInternal(target, value);
-+	}
-+
-+	/*
-+	 * This method starts the coroutine execution. It catches exception and handles a return from the run method.
-+	 */
-+	@Continuable
-+	final void start(Object value) {
-+		Object ret = null;
-+		RuntimeException e = null;
-+		try {
-+			ret = run(value);
-+		}
-+		catch (Throwable t) {
-+			if (t != exitException) {
-+				t.printStackTrace();
-+				e = new RuntimeException("coroutine terminated by exception", t);
-+			}
-+		}
-+		finally {
-+			try {
-+				context.coroutineRemoved(this);
-+			}
-+			catch (Throwable t) {
-+				t.printStackTrace();
-+			}
-+			if (last != this) {
-+				last.next = next;
-+				next.last = last;
-+				Coroutine temp = last;
-+				last = null;
-+				next = null;
-+				if (e != null)
-+					temp.exception = e;
-+				yieldToInternal(temp, ret);
-+			}
-+		}
-+	}
-+
-+	/**
-+	 * This implementation of the run method calls the CoRunnable.run method.
-+	 * @param value the value passed via yield
-+	 * @return the value that will be passed to the next coroutine
-+	 */
-+	protected Object run(Object value) {
-+		if (runnable != null)
-+			return runnable.run();
-+		else
-+			return null;
-+	}
-+}
-diff --git a/src/share/classes/javax/stack/CoroutineContext.java b/src/share/classes/javax/stack/CoroutineContext.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/CoroutineContext.java
-@@ -0,0 +1,85 @@
-+package javax.stack;
-+import javax.stack.Continuable;
-+import javax.stack.Continuation;
-+
-+/**
-+ * This class provides a context in which coroutines can be executed. Coroutines are added to a context either explicitly by
-+ * passing the context to the coroutine's constructor or implicitly by creating a coroutine while another coroutine of the context
-+ * is running.
-+ * 
-+ * @author lukas.stadler@jku.at
-+ */
-+public class CoroutineContext {
-+	private static ThreadLocal<CoroutineContext> current = new ThreadLocal<CoroutineContext>();
-+
-+	private CoroutineContext last;
-+	private Coroutine currentCoroutine;
-+
-+	Continuation startCoroutine = new Continuation();
-+
-+	@Continuable
-+	private void runInternal(Object value) {
-+		Object ret = startCoroutine.save();
-+		if (ret == Continuation.CAPTURED) {
-+			// System.out.println("start initial coroutine: " + value);
-+			currentCoroutine.start(value);
-+		}
-+		else {
-+			// System.out.println("start subsequent coroutine: " + ret);
-+			currentCoroutine.start(ret);
-+		}
-+	}
-+
-+	/**
-+	 * Starts the coroutine execution. The first coroutine that was created for this context will be the first one to run.
-+	 */
-+	public void start(Object value) {
-+		if (currentCoroutine == null)
-+			throw new IllegalStateException("Cannot start a context with no coroutines");
-+		last = current.get();
-+		current.set(this);
-+		runInternal(value);
-+		current.set(last);
-+		this.last = null;
-+	}
-+
-+	/**
-+	 * This method will be called every time a coroutine is added to this context
-+	 */
-+	void coroutineAdded(Coroutine coroutine) {
-+	}
-+
-+	/**
-+	 * This method will be called every time a coroutine ends (and is thus removed)
-+	 */
-+	void coroutineRemoved(Coroutine coroutine) {
-+	}
-+
-+	/**
-+	 * This method can be overridden to change the default scheduling behavior of a coroutine context.
-+	 * @param current the coroutine that is currently executed
-+	 * @return the coroutine to be executed next
-+	 */
-+	Coroutine scheduleNext(Coroutine current) {
-+		return current.getNext();
-+	}
-+
-+	/**
-+	 * @return the current context of the current thread, or null if there is no active context
-+	 */
-+	public static CoroutineContext getCurrent() {
-+		return current.get();
-+	}
-+
-+	/**
-+	 * @return the currently executing coroutine of this context (or the coroutine that will be executed first, if the context
-+	 *         hasn't started yet)
-+	 */
-+	public Coroutine getCurrentCoroutine() {
-+		return currentCoroutine;
-+	}
-+
-+	void setCurrentCoroutine(Coroutine coroutine) {
-+		currentCoroutine = coroutine;
-+	}
-+}
-diff --git a/src/share/classes/javax/stack/CoroutineExitException.java b/src/share/classes/javax/stack/CoroutineExitException.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/CoroutineExitException.java
-@@ -0,0 +1,5 @@
-+package javax.stack;
-+public class CoroutineExitException extends RuntimeException {
-+	private static final long serialVersionUID = -9155842264591995913L;
-+
-+}
-diff --git a/src/share/classes/javax/stack/DelimitedRunnable.java b/src/share/classes/javax/stack/DelimitedRunnable.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/DelimitedRunnable.java
-@@ -0,0 +1,27 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+public interface DelimitedRunnable {
-+	public void run(Continuation start, Object firstValue);
-+}
-diff --git a/src/share/classes/javax/stack/Fiber.java b/src/share/classes/javax/stack/Fiber.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/javax/stack/Fiber.java
-@@ -0,0 +1,69 @@
-+/*
-+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+package javax.stack;
-+
-+public abstract class Fiber {
-+	private Continuation returnContinuation;
-+	private Continuation continuation = new Continuation();
-+
-+	private class FiberRunnable implements DelimitedRunnable {
-+		@Continuable
-+		public final void run(Continuation start, Object firstValue) {
-+			returnContinuation = start;
-+			Object lastRetValue;
-+			try {
-+				lastRetValue = generate(firstValue);
-+			}
-+			catch (RuntimeException e) {
-+				e.printStackTrace();
-+				lastRetValue = null;
-+			}
-+			returnContinuation = null;
-+			start.resume(lastRetValue);
-+		}
-+	}
-+
-+	@Continuable
-+	protected abstract Object generate(Object firstIn);
-+
-+	@Continuable
-+	protected Object yield(Object returnValue) {
-+		Object o = continuation.save();
-+		if (o == Continuation.CAPTURED)
-+			returnContinuation.resume(returnValue);
-+		return o;
-+	}
-+
-+	@Continuable
-+	public Object resume(Object value) {
-+		if (returnContinuation == null)
-+			return Continuation.startDelimited(new FiberRunnable(), value);
-+		else
-+			return Continuation.continueDelimited(continuation, value);
-+	}
-+
-+	public void dump() {
-+		continuation.dump();
-+	}
-+
-+}
-diff --git a/test/javax/stack/ContinuationTest1.java b/test/javax/stack/ContinuationTest1.java
-new file mode 100644
---- /dev/null
-+++ b/test/javax/stack/ContinuationTest1.java
-@@ -0,0 +1,229 @@
-+package javax.stack;
-+
-+import static org.junit.Assert.assertEquals;
-+
-+import org.junit.Before;
-+import org.junit.Test;
-+
-+public class ContinuationTest1 extends ContinuationTestTools {
-+
-+	public ContinuationTest1() {
-+		interpreted = this;
-+		if (compiled == null)
-+			compiled = new ContinuationTest1Compiled();
-+	}
-+
-+	@Before
-+	public void setUp() throws Exception {
-+		clearActions();
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
-+		int i;
-+		cont.save();
-+		i = 0;
-+		i += a;
-+		i += b;
-+		i += c;
-+		i += d;
-+		i += e;
-+		assertEquals(15, i);
-+		assertEquals(ContinuationTest1.class, this.getClass());
-+		assertEquals(Continuation.class, cont.getClass());
-+		return 10102;
-+	}
-+
-+	private int cnt = 0;
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testRec() {
-+		Integer i = 100000;
-+		Continuation cont = new Continuation();
-+		assertEquals(10102, compiled.subSave(cont, 1, 2, 3, 4, 5));
-+		assertEquals(ContinuationTest1.class, this.getClass());
-+		if (cnt++ == 0) {
-+			cont.resume(null);
-+		}
-+		assertEquals(100000, i);
-+	}
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testSimple() {
-+		Continuation cont = new Continuation();
-+		action(1);
-+		if (cont.save() == Continuation.CAPTURED) {
-+			action(2);
-+			cont.resume(null);
-+			action(100);
-+		}
-+		else
-+			action(3);
-+
-+		action(4);
-+		assertActions(new int[] { 1, 2, 3, 4 });
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	int intSub(Continuation c, int code1, Integer code2, int depth) {
-+		if (depth == 0) {
-+			action(code1);
-+			intTemp = code1;
-+			objTemp = code2;
-+			thisTemp = this;
-+			lastSaveReturn = c.save();
-+			action(code2);
-+			assertEquals(thisTemp, this);
-+			assertEquals(intTemp, code1);
-+			assertEquals(objTemp, code2);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				compiled.intSub(c, code1, code2, depth - 1);
-+			else
-+				intSub(c, code1, code2, depth - 1);
-+		}
-+		return 101;
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
-+		if (depth == 0) {
-+			action(code1);
-+			intTemp = code1;
-+			objTemp = code2;
-+			thisTemp = this;
-+			lastSaveReturn = c.save();
-+			assertEquals(thisTemp, this);
-+			assertEquals(intTemp, code1);
-+			assertEquals(objTemp, code2);
-+			action(code2);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				compiled.objSub(c, code1, code2, depth - 1);
-+			else
-+				objSub(c, code1, code2, depth - 1);
-+		}
-+		return 201;
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	void resumeRec(Continuation c, Object retValue, int depth) {
-+		if (depth == 0) {
-+			c.resume(null);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				compiled.resumeRec(c, retValue, depth - 1);
-+			else
-+				resumeRec(c, retValue, depth - 1);
-+		}
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
-+		Continuation c = new Continuation();
-+		action(1);
-+		action(intSub(c, 2, 3, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(4);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(5);
-+		action(compiled.intSub(c, 6, 7, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(8);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(9);
-+		action(objSub(c, 10, 11, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(12);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(13);
-+		action(compiled.objSub(c, 14, 15, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(16);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(17);
-+		assertActions(new int[] { 1, 2, 3, 101, 4, 3, 101, 5, 6, 7, 102, 8, 7, 102, 9, 10, 11, 201, 12, 11, 201, 13, 14, 15, 202,
-+				16, 15, 202, 17 });
-+	}
-+
-+	@Test
-+	public void testParamsReturn() {
-+		for (int i2 = 1; i2 < 50; i2++) {
-+			for (int i = 0; i < 50; i++) {
-+//				System.out.println("resume: " + i + ", save: " + i2);
-+				pushActions();
-+				testParamsReturnInternal(i, i2);
-+				popActions();
-+			}
-+		}
-+	}
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testManyParams() {
-+		Continuation cont = new Continuation();
-+		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
-+				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
-+			cont.resume(null);
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f,
-+			long g, Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r,
-+			int s, int t, int u, int v) {
-+		final Object ret;
-+		if (depth > 0)
-+			ret = manyParamsSub(cont, depth - 1, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
-+		else
-+			ret = cont.save();
-+		assertEquals(cont.getClass(), Continuation.class);
-+		assertEquals(a, true);
-+		assertEquals(b, false);
-+		assertEquals(c, 1);
-+		assertEquals(d, (short) 2);
-+		assertEquals(e, (byte) 3);
-+		assertEquals(f, (char) 4);
-+		assertEquals(g, (long) 5);
-+		assertEquals(h, 6);
-+		assertEquals(i, (short) 7);
-+		assertEquals(j, (byte) 8);
-+		assertEquals(k, (char) 9);
-+		assertEquals(l, (long) 10);
-+		assertEquals(m, (float) 11);
-+		assertEquals(n, (double) 12);
-+		assertEquals(o, (float) 13);
-+		assertEquals(p, (double) 14);
-+		assertEquals(q, 15);
-+		assertEquals(r, 16);
-+		assertEquals(s, 17);
-+		assertEquals(t, 18);
-+		assertEquals(u, 19);
-+		assertEquals(v, 20);
-+		return ret;
-+	}
-+}
-diff --git a/test/javax/stack/ContinuationTest1Compiled.java b/test/javax/stack/ContinuationTest1Compiled.java
-new file mode 100644
---- /dev/null
-+++ b/test/javax/stack/ContinuationTest1Compiled.java
-@@ -0,0 +1,225 @@
-+package javax.stack;
-+
-+import static org.junit.Assert.assertEquals;
-+
-+import org.junit.Before;
-+import org.junit.Test;
-+
-+public class ContinuationTest1Compiled extends ContinuationTestTools {
-+
-+	public ContinuationTest1Compiled() {
-+		compiled = this;
-+		if (interpreted == null)
-+			interpreted = new ContinuationTest1();
-+	}
-+
-+	@Before
-+	public void setUp() throws Exception {
-+		clearActions();
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
-+		int i;
-+		cont.save();
-+		i = 0;
-+		i += a;
-+		i += b;
-+		i += c;
-+		i += d;
-+		i += e;
-+		assertEquals(15, i);
-+		assertEquals(ContinuationTest1Compiled.class, this.getClass());
-+		assertEquals(Continuation.class, cont.getClass());
-+		return 10102;
-+	}
-+
-+	private int cnt = 0;
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testRec() {
-+		Integer i = 100000;
-+		Continuation cont = new Continuation();
-+		assertEquals(10102, interpreted.subSave(cont, 1, 2, 3, 4, 5));
-+		assertEquals(ContinuationTest1Compiled.class, this.getClass());
-+		if (cnt++ == 0)
-+			cont.resume(null);
-+		assertEquals(100000, i);
-+	}
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testSimple() {
-+		Continuation cont = new Continuation();
-+		action(1);
-+		if (cont.save() == Continuation.CAPTURED) {
-+			action(2);
-+			cont.resume(null);
-+			action(100);
-+		}
-+		else
-+			action(3);
-+
-+		action(4);
-+		assertActions(new int[] { 1, 2, 3, 4 });
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	int intSub(Continuation c, int code1, Integer code2, int depth) {
-+		if (depth == 0) {
-+			action(code1);
-+			intTemp = code1;
-+			objTemp = code2;
-+			lastSaveReturn = c.save();
-+			assertEquals(intTemp, code1);
-+			assertEquals(objTemp, code2);
-+			action(code2);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				interpreted.intSub(c, code1, code2, depth - 1);
-+			else
-+				intSub(c, code1, code2, depth - 1);
-+		}
-+		return 102;
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
-+		if (depth == 0) {
-+			action(code1);
-+			intTemp = code1;
-+			objTemp = code2;
-+			lastSaveReturn = c.save();
-+			assertEquals(intTemp, code1);
-+			assertEquals(objTemp, code2);
-+			action(code2);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				interpreted.objSub(c, code1, code2, depth - 1);
-+			else
-+				objSub(c, code1, code2, depth - 1);
-+		}
-+		return 202;
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	void resumeRec(Continuation c, Object retValue, int depth) {
-+		if (depth == 0) {
-+			c.resume(null);
-+		}
-+		else {
-+			if ((depth & 3) == 0)
-+				interpreted.resumeRec(c, retValue, depth - 1);
-+			else
-+				resumeRec(c, retValue, depth - 1);
-+		}
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
-+		Continuation c = new Continuation();
-+		action(1);
-+		action(interpreted.intSub(c, 2, 3, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(4);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(5);
-+		action(intSub(c, 6, 7, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(8);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(9);
-+		action(interpreted.objSub(c, 10, 11, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(12);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(13);
-+		action(objSub(c, 14, 15, saveDepth));
-+		if (lastSaveReturn == Continuation.CAPTURED) {
-+			action(16);
-+			if (resumeDepth == 0)
-+				c.resume(null);
-+			else
-+				resumeRec(c, null, resumeDepth);
-+			action(100);
-+		}
-+		action(17);
-+		assertActions(new int[] { 1, 2, 3, 101, 4, 3, 101, 5, 6, 7, 102, 8, 7, 102, 9, 10, 11, 201, 12, 11, 201, 13, 14, 15, 202,
-+				16, 15, 202, 17 });
-+	}
-+
-+	@Test
-+	public void testParamsReturn() {
-+		for (int i2 = 0; i2 < 50; i2++) {
-+			for (int i = 0; i < 50; i++) {
-+				// System.out.println("resume: " + i + ", save: " + i2);
-+				pushActions();
-+				testParamsReturnInternal(i, i2);
-+				popActions();
-+			}
-+		}
-+	}
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testManyParams() {
-+		Continuation cont = new Continuation();
-+		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
-+				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
-+			cont.resume(null);
-+	}
-+
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f, long g,
-+			Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r, int s,
-+			int t, int u, int v) {
-+		final Object ret;
-+		if (depth > 0)
-+			ret = manyParamsSub(cont, depth - 1, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
-+		else
-+			ret = cont.save();
-+		assertEquals(cont.getClass(), Continuation.class);
-+		assertEquals(a, true);
-+		assertEquals(b, false);
-+		assertEquals(c, 1);
-+		assertEquals(d, (short) 2);
-+		assertEquals(e, (byte) 3);
-+		assertEquals(f, (char) 4);
-+		assertEquals(g, (long) 5);
-+		assertEquals(h, 6);
-+		assertEquals(i, (short) 7);
-+		assertEquals(j, (byte) 8);
-+		assertEquals(k, (char) 9);
-+		assertEquals(l, (long) 10);
-+		assertEquals(m, (float) 11);
-+		assertEquals(n, (double) 12);
-+		assertEquals(o, (float) 13);
-+		assertEquals(p, (double) 14);
-+		assertEquals(q, 15);
-+		assertEquals(r, 16);
-+		assertEquals(s, 17);
-+		assertEquals(t, 18);
-+		assertEquals(u, 19);
-+		assertEquals(v, 20);
-+		return ret;
-+	}
-+
-+}
-diff --git a/test/javax/stack/ContinuationTestTools.java b/test/javax/stack/ContinuationTestTools.java
-new file mode 100644
---- /dev/null
-+++ b/test/javax/stack/ContinuationTestTools.java
-@@ -0,0 +1,53 @@
-+package javax.stack;
-+
-+import static org.junit.Assert.assertEquals;
-+
-+import java.util.ArrayList;
-+import java.util.Stack;
-+
-+public class ContinuationTestTools {
-+	private static Stack<ArrayList<Integer>> actions = new Stack<ArrayList<Integer>>();
-+
-+	protected static Object thisTemp;
-+	protected static Object objTemp;
-+	protected static int intTemp;
-+	protected static Object lastSaveReturn = null;
-+
-+	protected static ContinuationTest1Compiled compiled;
-+	protected static ContinuationTest1 interpreted;
-+
-+	protected static void clearActions() {
-+		actions.clear();
-+		actions.add(new ArrayList<Integer>());
-+	}
-+
-+	protected static void pushActions() {
-+		actions.push(new ArrayList<Integer>());
-+	}
-+
-+	protected static void popActions() {
-+		actions.pop();
-+	}
-+
-+	protected static void action(int code) {
-+		actions.peek().add(code);
-+	}
-+
-+	protected static void assertActions(int[] expectedActions) {
-+		if (expectedActions.length == actions.peek().size()) {
-+			for (int i = 0; i < expectedActions.length; i++)
-+				assertEquals(expectedActions[i], actions.peek().get(i));
-+		}
-+		else {
-+			System.out.print("expected: ");
-+			for (int i = 0; i < expectedActions.length; i++)
-+				System.out.print(expectedActions[i] + " ");
-+			System.out.print("\nactual: ");
-+			for (int i = 0; i < actions.peek().size(); i++)
-+				System.out.print(actions.peek().get(i) + " ");
-+
-+			assertEquals(expectedActions.length, actions.peek().size());
-+		}
-+	}
-+
-+}
-diff --git a/test/javax/stack/DelimitedTest.java b/test/javax/stack/DelimitedTest.java
-new file mode 100644
---- /dev/null
-+++ b/test/javax/stack/DelimitedTest.java
-@@ -0,0 +1,47 @@
-+package javax.stack;
-+
-+import java.io.IOException;
-+
-+import org.junit.Test;
-+
-+public class DelimitedTest {
-+
-+	class TestFiber extends Fiber {
-+		@Continuable(ContinuableAccess.HIDDEN)
-+		protected Object generate(Object value) {
-+			int i = (Integer) value;
-+			while (true) {
-+				i += (Integer) yield(i);
-+			}
-+		}
-+	}
-+
-+	private static final long COUNT = 5000;
-+	private static final long COUNT2 = 100;
-+
-+	@Test
-+	@Continuable(ContinuableAccess.HIDDEN)
-+	public void testRec() throws IOException {
-+		try {
-+			Continuation cont = new Continuation();
-+			cont.save();
-+			do {
-+				long time = System.nanoTime();
-+				for (int i2 = 0; i2 < COUNT2; i2++) {
-+					TestFiber test = new TestFiber();
-+					for (int i = 0; i < COUNT; i++) {
-+						Object ret = test.resume(i);
-+						int result = (Integer) ret;
-+					}
-+				}
-+				long tps = (long) (COUNT * COUNT2 * 1000000000d / (System.nanoTime() - time));
-+				System.out.println(tps);
-+			}
-+			while (true);
-+		}
-+		catch (Throwable e) {
-+			e.printStackTrace();
-+		}
-+	}
-+
-+}
-\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callcc_old.patch	Thu Oct 28 15:14:50 2010 +0200
@@ -0,0 +1,1330 @@
+diff --git a/src/share/classes/javax/stack/CoRunnable.java b/src/share/classes/javax/stack/CoRunnable.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/CoRunnable.java
+@@ -0,0 +1,4 @@
++package javax.stack;
++public interface CoRunnable {
++	public Object run();
++}
+\ No newline at end of file
+diff --git a/src/share/classes/javax/stack/Continuable.java b/src/share/classes/javax/stack/Continuable.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/Continuable.java
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++import java.lang.annotation.*;
++
++@Documented
++@Retention(RetentionPolicy.RUNTIME)
++@Target(ElementType.METHOD)
++public @interface Continuable {
++	ContinuableAccess value() default ContinuableAccess.HIDDEN;
++}
+diff --git a/src/share/classes/javax/stack/ContinuableAccess.java b/src/share/classes/javax/stack/ContinuableAccess.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/ContinuableAccess.java
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++public enum ContinuableAccess {
++		HIDDEN, READONLY, READWRITE
++}
+diff --git a/src/share/classes/javax/stack/Continuation.java b/src/share/classes/javax/stack/Continuation.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/Continuation.java
+@@ -0,0 +1,115 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++/**
++ * @author lukas.stadler@jku.at
++ */
++@SuppressWarnings("unused")
++public class Continuation {
++	private static class CONTINUATION_CAPTURED {
++	}
++
++	public static final Object CAPTURED = CONTINUATION_CAPTURED.class;
++	private Object data;
++	private Thread thread;
++
++	private static native void registerNatives();
++
++	static {
++		registerNatives();
++	}
++
++	/**
++	 * Saves the current thread state into the continuation object
++	 * @return null if the continuation was saved or the value given to resume if it was resumed
++	 */
++	public final native Object save();
++
++	/**
++	 * Restores the stack to the state that it had when the continuation was saved.
++	 * @param retValue the value that the save method should return
++	 */
++	public final native void resume(Object retValue);
++
++	/**
++	 * Yields to the given target continuation, passing along the current continuation
++	 * @param target the continuation that will be reinstated
++	 */
++	@Continuable
++	public static final void yield(Continuation target) {
++		Continuation c = new Continuation();
++		if (c.save() == null)
++			target.resume(c);
++	}
++
++	/*
++	 * This method will be called by startDelimited
++	 */
++	@Continuable
++	private static final Object startDelimitedInternal(DelimitedRunnable runnable, Object firstValue) {
++		Continuation cont = new Continuation();
++		Object ret = cont.save();
++		if (ret == CAPTURED)
++			runnable.run(cont, firstValue);
++		return ret;
++	}
++
++	public static final native Object startDelimited(DelimitedRunnable runnable, Object firstValue);
++
++	/*
++	 * This method will be called by continueDelimited
++	 */
++	@Continuable
++	private static final Object continueDelimitedInternal(Continuation cont, Object value) {
++		cont.resume(value);
++		return null;
++	}
++
++	public static final native Object continueDelimited(Continuation continuation, Object value);
++
++	public final native Object dump();
++
++	private static final native Object storeFrameObject(Object retValue);
++
++	private static final native void storeFrameVoid();
++
++	private static final native boolean storeFrameBoolean(boolean retValue);
++
++	private static final native byte storeFrameByte(byte retValue);
++
++	private static final native char storeFrameChar(char retValue);
++
++	private static final native short storeFrameShort(short retValue);
++
++	private static final native int storeFrameInt(int retValue);
++
++	private static final native long storeFrameLong(long retValue);
++
++	private static final native float storeFrameFloat(float retValue);
++
++	private static final native double storeFrameDouble(double retValue);
++
++	private static final native Throwable unwind(Throwable e);
++
++}
+diff --git a/src/share/classes/javax/stack/ContinuationPermission.java b/src/share/classes/javax/stack/ContinuationPermission.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/ContinuationPermission.java
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++import java.security.BasicPermission;
++
++/* name is either "resumeSecure" or "resumeUnsecure" */
++public class ContinuationPermission extends BasicPermission {
++	private static final long serialVersionUID = -3608714945512368738L;
++
++	public ContinuationPermission(String name) {
++		super(name);
++	}
++}
+\ No newline at end of file
+diff --git a/src/share/classes/javax/stack/Coroutine.java b/src/share/classes/javax/stack/Coroutine.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/Coroutine.java
+@@ -0,0 +1,305 @@
++package javax.stack;
++import javax.stack.Continuable;
++import javax.stack.Continuation;
++
++/**
++ * Experimental coroutine implementation using the continuation framework.
++ * 
++ * This class works very much like the {@link Thread} class, it can either be supplied with a {@link CoRunnable} upon creation or
++ * the run method can be overridden.<br/>
++ * All coroutines belonging to a context are kept in a doubly-linked ring data structure. Due to this there is an ordering of
++ * coroutines, and the next and previous coroutines are known.
++ * 
++ * @author lukas.stadler@jku.at
++ */
++public class Coroutine {
++	// exception used to terminate/close coroutines, created only once because exception creation is expensive
++	private static final CoroutineExitException exitException = new CoroutineExitException();
++
++	// contains the actual stack frames, local variables, etc.
++	private Continuation data;
++
++	// the context this coroutine belongs to
++	private CoroutineContext context;
++
++	// the code that will be executed if run isn't overridden
++	private CoRunnable runnable;
++
++	// the pointers for the doubly-linked ring data structure
++	private Coroutine last;
++	private Coroutine next;
++
++	// if this is non-null then an exception will be raised when this coroutine is resumed
++	private RuntimeException exception;
++
++	/**
++	 * Creates a new coroutine that belongs to the currently active {@link CoroutineContext}. This constructor is only useful if
++	 * the run method is overridden. The coroutine will be inserted after the current coroutine of the context, or as the first
++	 * coroutine if it is the first one added to the context.
++	 * @throws IllegalThreadStateException if there is no current context
++	 */
++	public Coroutine() {
++		initialize(CoroutineContext.getCurrent());
++	}
++
++	/**
++	 * Creates a new coroutine that belongs to the currently active {@link CoroutineContext}. The coroutine will execute the given
++	 * CoRunnable (if it is non-null). The coroutine will be inserted after the current coroutine of the context, or as the first
++	 * coroutine if it is the first one added to the context.
++	 * @throws IllegalThreadStateException if there is no current context
++	 */
++	public Coroutine(CoRunnable runnable) {
++		this.runnable = runnable;
++		initialize(CoroutineContext.getCurrent());
++	}
++
++	/**
++	 * Creates a new coroutine that belongs to the given {@link CoroutineContext}. This constructor is only useful if the run
++	 * method is overridden. The coroutine will be inserted after the current coroutine of the context, or as the first coroutine
++	 * if it is the first one added to the context.
++	 * @throws IllegalArgumentException if context is null
++	 */
++	public Coroutine(CoroutineContext context) {
++		if (context == null)
++			throw new IllegalArgumentException("context cannot be null");
++		initialize(context);
++	}
++
++	/**
++	 * Creates a new coroutine that belongs to the given {@link CoroutineContext}. The coroutine will execute the given CoRunnable
++	 * (if it is non-null). The coroutine will be inserted after the current coroutine of the context, or as the first coroutine
++	 * if it is the first one added to the context.
++	 * @throws IllegalArgumentException if context is null
++	 */
++	public Coroutine(CoroutineContext context, CoRunnable runnable) {
++		if (context == null)
++			throw new IllegalArgumentException("context cannot be null");
++		this.runnable = runnable;
++		initialize(context);
++	}
++
++	/*
++	 * Adds this coroutine into the doubly-linked ring of the given context.
++	 */
++	private void initialize(CoroutineContext context) {
++		if (context == null)
++			throw new IllegalThreadStateException("Cannot create Coroutine without CoroutineContext");
++		context.coroutineAdded(this);
++		this.context = context;
++		if (context.getCurrentCoroutine() == null) {
++			last = this;
++			next = this;
++			context.setCurrentCoroutine(this);
++		}
++		else {
++			Coroutine current = context.getCurrentCoroutine();
++			last = current.last;
++			next = current;
++			current.last = this;
++			last.next = this;
++		}
++	}
++
++	/**
++	 * Yields to the target coroutine, without changing the order of the coroutines
++	 * @param target the coroutine that will be current after this call
++	 * @param value the value that is passed to the target coroutine
++	 * @return the value passed to the yield that makes this coroutine active again
++	 */
++	@Continuable
++	private Object yieldToInternal(Coroutine target, Object value) {
++		assert target != null;
++		// System.out.println("yield to " + target + ", value="+value);
++		context.setCurrentCoroutine(target);
++		if (data == null)
++			data = new Continuation();
++		Object ret = data.save();
++		try {
++			// System.out.println("ret="+ret);
++			if (ret == Continuation.CAPTURED) {
++				if (target.data == null)
++					context.startCoroutine.resume(value);
++				else {
++					// System.out.println("target resume");
++					target.data.resume(value);
++				}
++				return null;
++			}
++			else
++				return ret;
++		}
++		finally {
++			if (exception != null) {
++				// System.out.println("throwing exception in coroutine " + this + ": " + exception);
++				throw exception;
++			}
++		}
++	}
++
++	/**
++	 * Closes the coroutine. This will resume the coroutine and throw a {@link CoroutineExitException}. If it propagates down to
++	 * the starting method the coroutine will end. Thus coroutines can veto the close operation if they catch the
++	 * CoroutineExitException.
++	 */
++	@Continuable
++	public final void close() {
++		if (isActive()) {
++			exception = exitException;
++			if (context == CoroutineContext.getCurrent()) {
++				if (this == Coroutine.getCurrent())
++					throw exception;
++				else
++					try {
++						yieldTo(this, null);
++					}
++					catch (CoroutineExitException e) {
++						// ignore
++					}
++			}
++		}
++	}
++
++	/**
++	 * @return the currently active coroutine, or null if there is no current coroutine context
++	 */
++	public static Coroutine getCurrent() {
++		CoroutineContext currentContext = CoroutineContext.getCurrent();
++		return currentContext == null ? null : currentContext.getCurrentCoroutine();
++	}
++
++	/**
++	 * @return true if this coroutine hasn't ended yet
++	 */
++	public final boolean isActive() {
++		assert (next != null) == (last != null);
++		return next != null;
++	}
++
++	/**
++	 * @return the coroutine that is scheduled to be executed after this one
++	 */
++	public final Coroutine getNext() {
++		return next;
++	}
++
++	/**
++	 * @return the coroutine that was executed before this one
++	 */
++	public final Coroutine getLast() {
++		return last;
++	}
++
++	/**
++	 * @return the context this coroutine belongs to
++	 */
++	public final CoroutineContext getContext() {
++		return context;
++	}
++
++	/**
++	 * Yields to the next scheduled coroutine (as determined by the scheduling behavior of the coroutine context)
++	 * @param value the value to be passed to the next coroutine
++	 * @return the value passed to this coroutine when it is resumed
++	 */
++	@Continuable
++	public static Object yield(Object value) {
++		Coroutine current = getCurrent();
++		return yieldTo(current.context.scheduleNext(current), value);
++	}
++
++	/**
++	 * Yields to the last coroutine. This can be used to implement coroutines that generate values for a caller.
++	 * @param value the value to be passed to the next coroutine
++	 * @return the value passed to this coroutine when it is resumed
++	 */
++	@Continuable
++	public static Object yieldReturn(Object value) {
++		Coroutine current = getCurrent();
++		// System.out.println("current=" + current);
++		// System.out.println("last=" + current.last);
++		return current.yieldToInternal(current.last, value);
++	}
++
++	/**
++	 * Yields to the next coroutine (ignoring the scheduling behavior of the coroutine context). This does not change the
++	 * coroutine order.
++	 * @param value the value to be passed to the next coroutine
++	 * @return the value passed to this coroutine when it is resumed
++	 */
++	@Continuable
++	public static Object yieldNext(Object value) {
++		Coroutine current = getCurrent();
++		return current.yieldToInternal(current.next, value);
++	}
++
++	/**
++	 * Yields to the given coroutine (ignoring the scheduling behavior of the coroutine context). The coroutine order will be
++	 * changed so that the given coroutine is the next one.
++	 * @param target the coroutine to be executed next
++	 * @param value the value to be passed to the next coroutine
++	 * @return the value passed to this coroutine when it is resumed
++	 */
++	@Continuable
++	public static Object yieldTo(Coroutine target, Object value) {
++		Coroutine current = getCurrent();
++		if (target != current.next) {
++			// remove target from its current position
++			target.last.next = target.next;
++			target.next.last = target.last;
++			// add target at the current position
++			target.last = current;
++			target.next = current.next;
++			target.last.next = target;
++			target.next.last = target;
++		}
++		return current.yieldToInternal(target, value);
++	}
++
++	/*
++	 * This method starts the coroutine execution. It catches exception and handles a return from the run method.
++	 */
++	@Continuable
++	final void start(Object value) {
++		Object ret = null;
++		RuntimeException e = null;
++		try {
++			ret = run(value);
++		}
++		catch (Throwable t) {
++			if (t != exitException) {
++				t.printStackTrace();
++				e = new RuntimeException("coroutine terminated by exception", t);
++			}
++		}
++		finally {
++			try {
++				context.coroutineRemoved(this);
++			}
++			catch (Throwable t) {
++				t.printStackTrace();
++			}
++			if (last != this) {
++				last.next = next;
++				next.last = last;
++				Coroutine temp = last;
++				last = null;
++				next = null;
++				if (e != null)
++					temp.exception = e;
++				yieldToInternal(temp, ret);
++			}
++		}
++	}
++
++	/**
++	 * This implementation of the run method calls the CoRunnable.run method.
++	 * @param value the value passed via yield
++	 * @return the value that will be passed to the next coroutine
++	 */
++	protected Object run(Object value) {
++		if (runnable != null)
++			return runnable.run();
++		else
++			return null;
++	}
++}
+diff --git a/src/share/classes/javax/stack/CoroutineContext.java b/src/share/classes/javax/stack/CoroutineContext.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/CoroutineContext.java
+@@ -0,0 +1,85 @@
++package javax.stack;
++import javax.stack.Continuable;
++import javax.stack.Continuation;
++
++/**
++ * This class provides a context in which coroutines can be executed. Coroutines are added to a context either explicitly by
++ * passing the context to the coroutine's constructor or implicitly by creating a coroutine while another coroutine of the context
++ * is running.
++ * 
++ * @author lukas.stadler@jku.at
++ */
++public class CoroutineContext {
++	private static ThreadLocal<CoroutineContext> current = new ThreadLocal<CoroutineContext>();
++
++	private CoroutineContext last;
++	private Coroutine currentCoroutine;
++
++	Continuation startCoroutine = new Continuation();
++
++	@Continuable
++	private void runInternal(Object value) {
++		Object ret = startCoroutine.save();
++		if (ret == Continuation.CAPTURED) {
++			// System.out.println("start initial coroutine: " + value);
++			currentCoroutine.start(value);
++		}
++		else {
++			// System.out.println("start subsequent coroutine: " + ret);
++			currentCoroutine.start(ret);
++		}
++	}
++
++	/**
++	 * Starts the coroutine execution. The first coroutine that was created for this context will be the first one to run.
++	 */
++	public void start(Object value) {
++		if (currentCoroutine == null)
++			throw new IllegalStateException("Cannot start a context with no coroutines");
++		last = current.get();
++		current.set(this);
++		runInternal(value);
++		current.set(last);
++		this.last = null;
++	}
++
++	/**
++	 * This method will be called every time a coroutine is added to this context
++	 */
++	void coroutineAdded(Coroutine coroutine) {
++	}
++
++	/**
++	 * This method will be called every time a coroutine ends (and is thus removed)
++	 */
++	void coroutineRemoved(Coroutine coroutine) {
++	}
++
++	/**
++	 * This method can be overridden to change the default scheduling behavior of a coroutine context.
++	 * @param current the coroutine that is currently executed
++	 * @return the coroutine to be executed next
++	 */
++	Coroutine scheduleNext(Coroutine current) {
++		return current.getNext();
++	}
++
++	/**
++	 * @return the current context of the current thread, or null if there is no active context
++	 */
++	public static CoroutineContext getCurrent() {
++		return current.get();
++	}
++
++	/**
++	 * @return the currently executing coroutine of this context (or the coroutine that will be executed first, if the context
++	 *         hasn't started yet)
++	 */
++	public Coroutine getCurrentCoroutine() {
++		return currentCoroutine;
++	}
++
++	void setCurrentCoroutine(Coroutine coroutine) {
++		currentCoroutine = coroutine;
++	}
++}
+diff --git a/src/share/classes/javax/stack/CoroutineExitException.java b/src/share/classes/javax/stack/CoroutineExitException.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/CoroutineExitException.java
+@@ -0,0 +1,5 @@
++package javax.stack;
++public class CoroutineExitException extends RuntimeException {
++	private static final long serialVersionUID = -9155842264591995913L;
++
++}
+diff --git a/src/share/classes/javax/stack/DelimitedRunnable.java b/src/share/classes/javax/stack/DelimitedRunnable.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/DelimitedRunnable.java
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++public interface DelimitedRunnable {
++	public void run(Continuation start, Object firstValue);
++}
+diff --git a/src/share/classes/javax/stack/Fiber.java b/src/share/classes/javax/stack/Fiber.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/Fiber.java
+@@ -0,0 +1,69 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++package javax.stack;
++
++public abstract class Fiber {
++	private Continuation returnContinuation;
++	private Continuation continuation = new Continuation();
++
++	private class FiberRunnable implements DelimitedRunnable {
++		@Continuable
++		public final void run(Continuation start, Object firstValue) {
++			returnContinuation = start;
++			Object lastRetValue;
++			try {
++				lastRetValue = generate(firstValue);
++			}
++			catch (RuntimeException e) {
++				e.printStackTrace();
++				lastRetValue = null;
++			}
++			returnContinuation = null;
++			start.resume(lastRetValue);
++		}
++	}
++
++	@Continuable
++	protected abstract Object generate(Object firstIn);
++
++	@Continuable
++	protected Object yield(Object returnValue) {
++		Object o = continuation.save();
++		if (o == Continuation.CAPTURED)
++			returnContinuation.resume(returnValue);
++		return o;
++	}
++
++	@Continuable
++	public Object resume(Object value) {
++		if (returnContinuation == null)
++			return Continuation.startDelimited(new FiberRunnable(), value);
++		else
++			return Continuation.continueDelimited(continuation, value);
++	}
++
++	public void dump() {
++		continuation.dump();
++	}
++
++}
+diff --git a/test/javax/stack/ContinuationTest1.java b/test/javax/stack/ContinuationTest1.java
+new file mode 100644
+--- /dev/null
++++ b/test/javax/stack/ContinuationTest1.java
+@@ -0,0 +1,229 @@
++package javax.stack;
++
++import static org.junit.Assert.assertEquals;
++
++import org.junit.Before;
++import org.junit.Test;
++
++public class ContinuationTest1 extends ContinuationTestTools {
++
++	public ContinuationTest1() {
++		interpreted = this;
++		if (compiled == null)
++			compiled = new ContinuationTest1Compiled();
++	}
++
++	@Before
++	public void setUp() throws Exception {
++		clearActions();
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
++		int i;
++		cont.save();
++		i = 0;
++		i += a;
++		i += b;
++		i += c;
++		i += d;
++		i += e;
++		assertEquals(15, i);
++		assertEquals(ContinuationTest1.class, this.getClass());
++		assertEquals(Continuation.class, cont.getClass());
++		return 10102;
++	}
++
++	private int cnt = 0;
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testRec() {
++		Integer i = 100000;
++		Continuation cont = new Continuation();
++		assertEquals(10102, compiled.subSave(cont, 1, 2, 3, 4, 5));
++		assertEquals(ContinuationTest1.class, this.getClass());
++		if (cnt++ == 0) {
++			cont.resume(null);
++		}
++		assertEquals(100000, i);
++	}
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testSimple() {
++		Continuation cont = new Continuation();
++		action(1);
++		if (cont.save() == Continuation.CAPTURED) {
++			action(2);
++			cont.resume(null);
++			action(100);
++		}
++		else
++			action(3);
++
++		action(4);
++		assertActions(new int[] { 1, 2, 3, 4 });
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	int intSub(Continuation c, int code1, Integer code2, int depth) {
++		if (depth == 0) {
++			action(code1);
++			intTemp = code1;
++			objTemp = code2;
++			thisTemp = this;
++			lastSaveReturn = c.save();
++			action(code2);
++			assertEquals(thisTemp, this);
++			assertEquals(intTemp, code1);
++			assertEquals(objTemp, code2);
++		}
++		else {
++			if ((depth & 3) == 0)
++				compiled.intSub(c, code1, code2, depth - 1);
++			else
++				intSub(c, code1, code2, depth - 1);
++		}
++		return 101;
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
++		if (depth == 0) {
++			action(code1);
++			intTemp = code1;
++			objTemp = code2;
++			thisTemp = this;
++			lastSaveReturn = c.save();
++			assertEquals(thisTemp, this);
++			assertEquals(intTemp, code1);
++			assertEquals(objTemp, code2);
++			action(code2);
++		}
++		else {
++			if ((depth & 3) == 0)
++				compiled.objSub(c, code1, code2, depth - 1);
++			else
++				objSub(c, code1, code2, depth - 1);
++		}
++		return 201;
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	void resumeRec(Continuation c, Object retValue, int depth) {
++		if (depth == 0) {
++			c.resume(null);
++		}
++		else {
++			if ((depth & 3) == 0)
++				compiled.resumeRec(c, retValue, depth - 1);
++			else
++				resumeRec(c, retValue, depth - 1);
++		}
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
++		Continuation c = new Continuation();
++		action(1);
++		action(intSub(c, 2, 3, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(4);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(5);
++		action(compiled.intSub(c, 6, 7, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(8);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(9);
++		action(objSub(c, 10, 11, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(12);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(13);
++		action(compiled.objSub(c, 14, 15, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(16);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(17);
++		assertActions(new int[] { 1, 2, 3, 101, 4, 3, 101, 5, 6, 7, 102, 8, 7, 102, 9, 10, 11, 201, 12, 11, 201, 13, 14, 15, 202,
++				16, 15, 202, 17 });
++	}
++
++	@Test
++	public void testParamsReturn() {
++		for (int i2 = 1; i2 < 50; i2++) {
++			for (int i = 0; i < 50; i++) {
++//				System.out.println("resume: " + i + ", save: " + i2);
++				pushActions();
++				testParamsReturnInternal(i, i2);
++				popActions();
++			}
++		}
++	}
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testManyParams() {
++		Continuation cont = new Continuation();
++		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
++				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
++			cont.resume(null);
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f,
++			long g, Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r,
++			int s, int t, int u, int v) {
++		final Object ret;
++		if (depth > 0)
++			ret = manyParamsSub(cont, depth - 1, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
++		else
++			ret = cont.save();
++		assertEquals(cont.getClass(), Continuation.class);
++		assertEquals(a, true);
++		assertEquals(b, false);
++		assertEquals(c, 1);
++		assertEquals(d, (short) 2);
++		assertEquals(e, (byte) 3);
++		assertEquals(f, (char) 4);
++		assertEquals(g, (long) 5);
++		assertEquals(h, 6);
++		assertEquals(i, (short) 7);
++		assertEquals(j, (byte) 8);
++		assertEquals(k, (char) 9);
++		assertEquals(l, (long) 10);
++		assertEquals(m, (float) 11);
++		assertEquals(n, (double) 12);
++		assertEquals(o, (float) 13);
++		assertEquals(p, (double) 14);
++		assertEquals(q, 15);
++		assertEquals(r, 16);
++		assertEquals(s, 17);
++		assertEquals(t, 18);
++		assertEquals(u, 19);
++		assertEquals(v, 20);
++		return ret;
++	}
++}
+diff --git a/test/javax/stack/ContinuationTest1Compiled.java b/test/javax/stack/ContinuationTest1Compiled.java
+new file mode 100644
+--- /dev/null
++++ b/test/javax/stack/ContinuationTest1Compiled.java
+@@ -0,0 +1,225 @@
++package javax.stack;
++
++import static org.junit.Assert.assertEquals;
++
++import org.junit.Before;
++import org.junit.Test;
++
++public class ContinuationTest1Compiled extends ContinuationTestTools {
++
++	public ContinuationTest1Compiled() {
++		compiled = this;
++		if (interpreted == null)
++			interpreted = new ContinuationTest1();
++	}
++
++	@Before
++	public void setUp() throws Exception {
++		clearActions();
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
++		int i;
++		cont.save();
++		i = 0;
++		i += a;
++		i += b;
++		i += c;
++		i += d;
++		i += e;
++		assertEquals(15, i);
++		assertEquals(ContinuationTest1Compiled.class, this.getClass());
++		assertEquals(Continuation.class, cont.getClass());
++		return 10102;
++	}
++
++	private int cnt = 0;
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testRec() {
++		Integer i = 100000;
++		Continuation cont = new Continuation();
++		assertEquals(10102, interpreted.subSave(cont, 1, 2, 3, 4, 5));
++		assertEquals(ContinuationTest1Compiled.class, this.getClass());
++		if (cnt++ == 0)
++			cont.resume(null);
++		assertEquals(100000, i);
++	}
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testSimple() {
++		Continuation cont = new Continuation();
++		action(1);
++		if (cont.save() == Continuation.CAPTURED) {
++			action(2);
++			cont.resume(null);
++			action(100);
++		}
++		else
++			action(3);
++
++		action(4);
++		assertActions(new int[] { 1, 2, 3, 4 });
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	int intSub(Continuation c, int code1, Integer code2, int depth) {
++		if (depth == 0) {
++			action(code1);
++			intTemp = code1;
++			objTemp = code2;
++			lastSaveReturn = c.save();
++			assertEquals(intTemp, code1);
++			assertEquals(objTemp, code2);
++			action(code2);
++		}
++		else {
++			if ((depth & 3) == 0)
++				interpreted.intSub(c, code1, code2, depth - 1);
++			else
++				intSub(c, code1, code2, depth - 1);
++		}
++		return 102;
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
++		if (depth == 0) {
++			action(code1);
++			intTemp = code1;
++			objTemp = code2;
++			lastSaveReturn = c.save();
++			assertEquals(intTemp, code1);
++			assertEquals(objTemp, code2);
++			action(code2);
++		}
++		else {
++			if ((depth & 3) == 0)
++				interpreted.objSub(c, code1, code2, depth - 1);
++			else
++				objSub(c, code1, code2, depth - 1);
++		}
++		return 202;
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	void resumeRec(Continuation c, Object retValue, int depth) {
++		if (depth == 0) {
++			c.resume(null);
++		}
++		else {
++			if ((depth & 3) == 0)
++				interpreted.resumeRec(c, retValue, depth - 1);
++			else
++				resumeRec(c, retValue, depth - 1);
++		}
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
++		Continuation c = new Continuation();
++		action(1);
++		action(interpreted.intSub(c, 2, 3, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(4);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(5);
++		action(intSub(c, 6, 7, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(8);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(9);
++		action(interpreted.objSub(c, 10, 11, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(12);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(13);
++		action(objSub(c, 14, 15, saveDepth));
++		if (lastSaveReturn == Continuation.CAPTURED) {
++			action(16);
++			if (resumeDepth == 0)
++				c.resume(null);
++			else
++				resumeRec(c, null, resumeDepth);
++			action(100);
++		}
++		action(17);
++		assertActions(new int[] { 1, 2, 3, 101, 4, 3, 101, 5, 6, 7, 102, 8, 7, 102, 9, 10, 11, 201, 12, 11, 201, 13, 14, 15, 202,
++				16, 15, 202, 17 });
++	}
++
++	@Test
++	public void testParamsReturn() {
++		for (int i2 = 0; i2 < 50; i2++) {
++			for (int i = 0; i < 50; i++) {
++				// System.out.println("resume: " + i + ", save: " + i2);
++				pushActions();
++				testParamsReturnInternal(i, i2);
++				popActions();
++			}
++		}
++	}
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testManyParams() {
++		Continuation cont = new Continuation();
++		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
++				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
++			cont.resume(null);
++	}
++
++	@Continuable(ContinuableAccess.HIDDEN)
++	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f, long g,
++			Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r, int s,
++			int t, int u, int v) {
++		final Object ret;
++		if (depth > 0)
++			ret = manyParamsSub(cont, depth - 1, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
++		else
++			ret = cont.save();
++		assertEquals(cont.getClass(), Continuation.class);
++		assertEquals(a, true);
++		assertEquals(b, false);
++		assertEquals(c, 1);
++		assertEquals(d, (short) 2);
++		assertEquals(e, (byte) 3);
++		assertEquals(f, (char) 4);
++		assertEquals(g, (long) 5);
++		assertEquals(h, 6);
++		assertEquals(i, (short) 7);
++		assertEquals(j, (byte) 8);
++		assertEquals(k, (char) 9);
++		assertEquals(l, (long) 10);
++		assertEquals(m, (float) 11);
++		assertEquals(n, (double) 12);
++		assertEquals(o, (float) 13);
++		assertEquals(p, (double) 14);
++		assertEquals(q, 15);
++		assertEquals(r, 16);
++		assertEquals(s, 17);
++		assertEquals(t, 18);
++		assertEquals(u, 19);
++		assertEquals(v, 20);
++		return ret;
++	}
++
++}
+diff --git a/test/javax/stack/ContinuationTestTools.java b/test/javax/stack/ContinuationTestTools.java
+new file mode 100644
+--- /dev/null
++++ b/test/javax/stack/ContinuationTestTools.java
+@@ -0,0 +1,53 @@
++package javax.stack;
++
++import static org.junit.Assert.assertEquals;
++
++import java.util.ArrayList;
++import java.util.Stack;
++
++public class ContinuationTestTools {
++	private static Stack<ArrayList<Integer>> actions = new Stack<ArrayList<Integer>>();
++
++	protected static Object thisTemp;
++	protected static Object objTemp;
++	protected static int intTemp;
++	protected static Object lastSaveReturn = null;
++
++	protected static ContinuationTest1Compiled compiled;
++	protected static ContinuationTest1 interpreted;
++
++	protected static void clearActions() {
++		actions.clear();
++		actions.add(new ArrayList<Integer>());
++	}
++
++	protected static void pushActions() {
++		actions.push(new ArrayList<Integer>());
++	}
++
++	protected static void popActions() {
++		actions.pop();
++	}
++
++	protected static void action(int code) {
++		actions.peek().add(code);
++	}
++
++	protected static void assertActions(int[] expectedActions) {
++		if (expectedActions.length == actions.peek().size()) {
++			for (int i = 0; i < expectedActions.length; i++)
++				assertEquals(expectedActions[i], actions.peek().get(i));
++		}
++		else {
++			System.out.print("expected: ");
++			for (int i = 0; i < expectedActions.length; i++)
++				System.out.print(expectedActions[i] + " ");
++			System.out.print("\nactual: ");
++			for (int i = 0; i < actions.peek().size(); i++)
++				System.out.print(actions.peek().get(i) + " ");
++
++			assertEquals(expectedActions.length, actions.peek().size());
++		}
++	}
++
++}
+diff --git a/test/javax/stack/DelimitedTest.java b/test/javax/stack/DelimitedTest.java
+new file mode 100644
+--- /dev/null
++++ b/test/javax/stack/DelimitedTest.java
+@@ -0,0 +1,47 @@
++package javax.stack;
++
++import java.io.IOException;
++
++import org.junit.Test;
++
++public class DelimitedTest {
++
++	class TestFiber extends Fiber {
++		@Continuable(ContinuableAccess.HIDDEN)
++		protected Object generate(Object value) {
++			int i = (Integer) value;
++			while (true) {
++				i += (Integer) yield(i);
++			}
++		}
++	}
++
++	private static final long COUNT = 5000;
++	private static final long COUNT2 = 100;
++
++	@Test
++	@Continuable(ContinuableAccess.HIDDEN)
++	public void testRec() throws IOException {
++		try {
++			Continuation cont = new Continuation();
++			cont.save();
++			do {
++				long time = System.nanoTime();
++				for (int i2 = 0; i2 < COUNT2; i2++) {
++					TestFiber test = new TestFiber();
++					for (int i = 0; i < COUNT; i++) {
++						Object ret = test.resume(i);
++						int result = (Integer) ret;
++					}
++				}
++				long tps = (long) (COUNT * COUNT2 * 1000000000d / (System.nanoTime() - time));
++				System.out.println(tps);
++			}
++			while (true);
++		}
++		catch (Throwable e) {
++			e.printStackTrace();
++		}
++	}
++
++}
+\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/continuation.patch	Thu Oct 28 15:14:50 2010 +0200
@@ -0,0 +1,1316 @@
+diff --git a/src/share/classes/sun/misc/Continuation.java b/src/share/classes/sun/misc/Continuation.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/sun/misc/Continuation.java
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++package sun.misc;
++
++/**
++ * The JVM Continuation class. The API design is still in progress.
++ *
++ * @author Hiroshi Yamauchi
++ */
++public class Continuation {
++
++    private static native void registerNatives();
++    static {
++        registerNatives();
++    }
++
++    /**
++     * The stack frames data
++     */
++    protected volatile Object stack;
++
++    /**
++     * The list of compiled code PCs in the stack. Needed to reclaim
++     * the compiled code in the code cache.
++     */
++    protected volatile long[] pcs;
++
++    /**
++     * A data field for convenience. This field is set to the second
++     * <code>data</code> parameter to {@link #enter} upon a {@link
++     * #save} call.
++     *
++     * <p>For example, this field can be used to pass some data from
++     * a scope entry point (a {@link #enter} call site) to the
++     * continuation resume point.
++     */
++    protected volatile Object data1;
++
++    /**
++     * A simple data field for convenience. For example, this field
++     * can be used to pass some data from the continuation save
++     * point to the continuation resume point.
++     */
++    protected volatile Object data2;   // the user-defined data
++
++    public Object data1() { synchronized(this) { return data1; } }
++    public Object data2() { synchronized(this) { return data2; } }
++    public void set_data1(Object o) { synchronized(this) { data1 = o; } }
++    public void set_data2(Object o) { synchronized(this) { data2 = o; } }
++    public boolean isSaved() { return stack != null; }
++
++    /**
++     * The continuation may save the compiled stack frames. The
++     * reference count of the compiled code (nmethod) is incremented
++     * upon a continuation save and decremented by this finalizer.
++     */
++    protected void finalize() throws Throwable {
++        if (pcs == null || pcs.length == 0) {
++            return;
++        }
++        for (long pc : pcs) {
++            dec_code_cache_ref_count(pc);
++        }
++    }
++
++    /**
++     * Copies the stack frames in the current scope, and stores them
++     * in this object.  This method must be called in an enclosing
++     * scope. Calling this method causes the stack frames in the
++     * scope to suspend (including the current frame) and the enter
++     * call at the entry of the current scope to return.
++     *
++     * @return the parameter passed to the resume call when the saved stack
++     *         frames are resumed in the future.
++     */
++    public Object save() {
++        return save_cont(this);
++    }
++
++    /**
++     * Reactivates the stack frames saved in this object on the
++     * current thread.  Overwrites the stack frames in the current
++     * scope with the saved stack frames.  This method must be
++     * called in an enclosing scope. Calling this method causes the
++     * suspended save call to resume from the point where it was
++     * suspended.
++     *
++     * @param rv the value to be returned from the resumed save call site.
++     */
++    public void resume(Object rv) {
++        if (stack == null) {
++            throw new IllegalArgumentException(
++                "Continuation hasn't been saved or tried to resume for a second time.");
++        }
++        Object s = stack;
++        stack = null; // resumable only once
++        resume_cont(s, rv);
++    }
++
++    /**
++     * Marks the beginning of a new 'scope' in preparation for stack
++     * save/resume.  Executes the given Runnable.
++     *
++     * @param data any user defined data to be passed from this call
++     *             site to the point where {@link #resume} is called
++     *             for convenience. The {@link #data1} field will be
++     *             set to this object.
++     * @return the Continuation object after the scope was saved
++     *         into a Continuation object or null if it wasn't and
++     *         simply returned
++     */
++    public static Object enter(Runnable r, Object data) {
++        Object rv = enter0(r, data);
++        return rv;
++    }
++
++    /*
++     * This method currently exists just for convenience for the
++     * continuation implementation in the JVM. This method along with
++     * enter() above will never be jitted. This may go away in the
++     * future.
++     */
++    private static Object enter0(Runnable r, Object data) {
++        Object rv = enter1(r, data);
++        return rv;
++    }
++
++    /*
++     * This method currently exists just for convenience for the
++     * continuation implementation in the JVM. This may go away in the
++     * future.
++     */
++    private static Object enter1(Runnable r, Object data) {
++        r.run();
++        return null; // If saved, this will return the CSE.
++    }
++
++    private static native Object save_cont(Continuation cont);
++    private static native void resume_cont(Object stack, Object rv);
++    private static native void dec_code_cache_ref_count(long pc);
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest1.java b/test/sun/misc/Continuation/ContinuationTest1.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest1.java
+@@ -0,0 +1,248 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import java.util.*;
++import sun.misc.Continuation;
++
++/*
++ * Basic tests for Continuation.
++ */
++public class ContinuationTest1 {
++
++    public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
++        int i;
++        cont.save();
++        i = 0;
++        i += a;
++        i += b;
++        i += c;
++        i += d;
++        i += e;
++        assertEquals(15, i);
++        return 10102;
++    }
++
++    private int cnt = 0;
++
++    public void testRec() {
++        final Continuation c = new Continuation();
++        Runnable r1 = new Runnable() {
++            public void run() {
++                assertEquals(10102, subSave(c, 1, 2, 3, 4, 5));
++            }
++          };
++        Continuation.enter(r1, null);
++        Runnable r2 = new Runnable() {
++            public void run() {
++                c.resume(null);
++            }
++          };
++        Continuation.enter(r2, null);
++        System.out.println("testRec   : PASS");
++    }
++
++    public void testSimple() {
++        final List<Integer> actions = new LinkedList<Integer>();
++        final Continuation c = new Continuation();
++        String data1 = "data1";
++        Runnable r1 = new Runnable() {
++            public void run() {
++                actions.add(1);
++                c.save();
++                actions.add(3);
++            }
++          };
++        Continuation.enter(r1, data1);
++        Runnable r2 = new Runnable() {
++            public void run() {
++                actions.add(2);
++                c.resume(null);
++                actions.add(100);
++            }
++          };
++        Continuation.enter(r2, null);
++        assertIdentity(c.data1(), data1);
++        assertEquals(actions.size(), 3);
++        assertEquals(actions.get(0), 1);
++        assertEquals(actions.get(1), 2);
++        assertEquals(actions.get(2), 3);
++        System.out.println("testSimple: PASS");
++    }
++
++    // If a monitor is held when a continuation is attempted to be saved,
++    // an exception should be thrown.
++    public void testMonitors() {
++        final Continuation c = new Continuation();
++        final Object lock = new Object();
++        Runnable r1 = new Runnable() {
++            public void run() {
++                synchronized(lock) {
++                    c.save(); // this should throw an exception
++                    assertTrue(false);
++                }
++                assertTrue(false);
++            }
++          };
++        try {
++            Continuation.enter(r1, null);
++        } catch (Throwable t) {
++            System.out.println("testMonitors: PASS");
++            return;
++        }
++        assertTrue(false);
++    }
++
++    // If the continuation is attempted to be resumed twice, an
++    // exception should be thrown.
++    public void testDoubleResume() {
++        final Continuation c = new Continuation();
++        final Object lock = new Object();
++        Runnable r1 = new Runnable() {
++            public void run() {
++                c.save();
++            }
++          };
++        Continuation.enter(r1, null);
++        Runnable r2 = new Runnable() {
++            public void run() {
++                c.resume(null);
++            }
++          };
++        Continuation.enter(r2, null);
++        try {
++            Continuation.enter(r2, null);
++        } catch (Throwable t) {
++            System.out.println("testDoubleResume: PASS");
++            return;
++        }
++        assertTrue(false);
++    }
++
++    public void testData1() throws Exception {
++        final Continuation c = new Continuation();
++        final Object data1 = new Object();
++        Runnable r1 = new Runnable() {
++            public void run() {
++                c.save();
++                assertIdentity(c.data1(), data1);
++            }
++          };
++        Continuation.enter(r1, data1);
++        assertIdentity(c.data1(), data1);
++        Runnable r2 = new Runnable() {
++            public void run() {
++                Runnable r3 = new Runnable() {
++                    public void run() {
++                        c.resume(null);
++                    }
++                  };
++                Continuation.enter(r3, null);
++            }
++          };
++        Thread t = new Thread(r2);
++        t.start();
++        t.join();
++        System.out.println("testData1: PASS");
++    }
++
++    public void testManyParams() {
++        final Continuation c = new Continuation();
++        Runnable r1 = new Runnable() {
++            public void run() {
++                Object rv = manyParamsSub(c, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
++                                          (long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20);
++                assertEquals(43, rv);
++            }
++          };
++        Continuation.enter(r1, null);
++        Runnable r2 = new Runnable() {
++            public void run() {
++                c.resume(43);
++            }
++          };
++        Continuation.enter(r2, null);
++        System.out.println("testManyParams: PASS");
++    }
++
++    private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f,
++                                 long g, Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r,
++                                 int s, int t, int u, int v) {
++        final Object ret;
++        if (depth > 0)
++            ret = manyParamsSub(cont, depth - 1, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
++        else
++            ret = cont.save();
++        assertEquals(a, true);
++        assertEquals(b, false);
++        assertEquals(c, 1);
++        assertEquals(d, (short) 2);
++        assertEquals(e, (byte) 3);
++        assertEquals(f, (char) 4);
++        assertEquals(g, (long) 5);
++        assertEquals(h, 6);
++        assertEquals(i, (short) 7);
++        assertEquals(j, (byte) 8);
++        assertEquals(k, (char) 9);
++        assertEquals(l, (long) 10);
++        assertEquals(m, (float) 11);
++        assertEquals(n, (double) 12);
++        assertEquals(o, (float) 13);
++        assertEquals(p, (double) 14);
++        assertEquals(q, 15);
++        assertEquals(r, 16);
++        assertEquals(s, 17);
++        assertEquals(t, 18);
++        assertEquals(u, 19);
++        assertEquals(v, 20);
++        return ret;
++    }
++
++    public static void main(String[] args) throws Exception {
++        ContinuationTest1 test = new ContinuationTest1();
++        test.testSimple();
++        test.testData1();
++        test.testRec();
++        test.testManyParams();
++        test.testMonitors();
++        test.testDoubleResume();
++    }
++
++    private static void assertTrue(boolean cond) {
++        if (!cond) {
++            throw new RuntimeException("assertion failed");
++        }
++    }
++
++    private static void assertEquals(Object o1, Object o2) {
++        if (!o1.equals(o2)) {
++            throw new RuntimeException("assertion failed: [" + o1 + "] != [" + o2 + "]");
++        }
++    }
++
++    private static void assertIdentity(Object o1, Object o2) {
++        if (o1 != o2) {
++            throw new RuntimeException("assertion failed: [" + o1 + "] != [" + o2 + "]");
++        }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest2.java b/test/sun/misc/Continuation/ContinuationTest2.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest2.java
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++
++/*
++ * Tests a simple continuation save/resume in the same thread.
++ */
++public class ContinuationTest2 {
++
++    public static void main(String[] args) {
++        Object rv = Continuation.enter(
++            new Runnable() {
++              public void run() {
++                  System.out.println(ContinuationTestBase.gammon1());
++              }
++            }, null);
++        System.out.println("main: " + rv);
++        final Continuation cont = (Continuation) rv;
++        Object rv1 = Continuation.enter(
++            new Runnable() {
++              public void run() {
++                cont.resume("resuming");
++              }
++            }, null);
++        System.out.println("main2");
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest3.java b/test/sun/misc/Continuation/ContinuationTest3.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest3.java
+@@ -0,0 +1,63 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++
++/*
++ * Tests a simple continuation save/resume between two threads in a
++ * loop.
++ *
++ * The two threads synchronize via a join.
++ */
++public class ContinuationTest3 {
++
++    public static void main(String[] args) throws Exception {
++      for(int i = 0; i < 10; ++i) {
++        Object rv = Continuation.enter(
++            new Runnable() {
++              public void run() {
++                System.out.println(ContinuationTestBase.gammon2(65000));
++              }
++            }, null);
++        System.out.println("main: " + rv);
++        final Continuation cont = (Continuation) rv;
++        System.out.println("cont: " + cont);
++        Runnable r = new Runnable() {
++            public void run() {
++                Object rv1 = Continuation.enter(
++                    new Runnable() {
++                        public void run() {
++                          cont.resume("resuming");
++                        }
++                    }, null);
++                System.out.println("thread end");
++            }
++          };
++        Thread t = new Thread(r);
++        t.start();
++        t.join();
++        System.out.println("main2");
++      }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest4.java b/test/sun/misc/Continuation/ContinuationTest4.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest4.java
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++
++/*
++ * Tests a simple continuation save/resume between two threads in a loop.
++ *
++ * Deoptimizations happen.
++ *
++ * The two threads synchronize via a join.
++ */
++public class ContinuationTest4 {
++
++    public static void main(String[] args) throws Exception {
++      for(int i = 0; i < 10; ++i) {
++        Object rv = Continuation.enter(
++            new Runnable() {
++              public void run() {
++                System.out.println(ContinuationTestBase.gammon3(true));
++              }
++            }, null);
++        System.out.println("main: " + rv);
++        final Continuation cont = (Continuation) rv;
++        System.out.println("cont: " + cont);
++        ContinuationTestBase.gammon3(false); // induce deopt of gammon3
++        Runnable r = new Runnable() {
++            public void run() {
++                Object rv1 = Continuation.enter(
++                    new Runnable() {
++                        public void run() {
++                            cont.resume("resuming");
++                        }
++                    }, null);
++                System.out.println("thread end");
++            }
++          };
++        Thread t = new Thread(r);
++        t.start();
++        t.join();
++        System.out.println("main2");
++      }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest5.java b/test/sun/misc/Continuation/ContinuationTest5.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest5.java
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++
++/*
++ * Tests a simple continuation save/resume between two threads in a loop.
++ *
++ * The two threads do not synchronize via a join.
++ */
++public class ContinuationTest5 {
++
++    public static void main(String[] args) throws Exception {
++      for(int i = 0; i < 10; ++i) {
++        Object rv = Continuation.enter(
++            new Runnable() {
++                public void run() {
++                    System.out.println(ContinuationTestBase.gammon2(65000));
++                }
++            }, null);
++        System.out.println("main: " + rv);
++        final Continuation cont = (Continuation) rv;
++        System.out.println("cont: " + cont);
++        Runnable r = new Runnable() {
++            public void run() {
++                Object rv1 = Continuation.enter(
++                    new Runnable() {
++                        public void run() {
++                            cont.resume("resuming");
++                        }
++                    }, null);
++                System.out.println("thread end");
++            }
++          };
++        Thread t = new Thread(r);
++        t.start();
++        System.out.println("main2");
++      }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest6.java b/test/sun/misc/Continuation/ContinuationTest6.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest6.java
+@@ -0,0 +1,64 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++
++/*
++ * Tests a simple continuation save/resume between two threads in a loop.
++ *
++ * Deoptimization happen.
++ *
++ * The two threads do not synchronize via a join.
++ */
++public class ContinuationTest6 {
++
++    public static void main(String[] args) throws Exception {
++      for(int i = 0; i < 10; ++i) {
++        Object rv = Continuation.enter(
++            new Runnable() {
++                public void run() {
++                    System.out.println(ContinuationTestBase.gammon3(true));
++                }
++            }, null);
++        System.out.println("main: " + rv);
++        final Continuation cont = (Continuation) rv;
++        System.out.println("cont: " + cont);
++        ContinuationTestBase.gammon3(false); // induce deopt of gammon
++        Runnable r = new Runnable() {
++            public void run() {
++                Object rv1 = Continuation.enter(
++                    new Runnable() {
++                        public void run() {
++                            cont.resume("resuming");
++                        }
++                    }, null);
++                System.out.println("thread end");
++            }
++          };
++        Thread t = new Thread(r);
++        t.start();
++        System.out.println("main2");
++      }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest7.java b/test/sun/misc/Continuation/ContinuationTest7.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest7.java
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++import java.util.concurrent.CountDownLatch;
++
++/*
++ * Tests a save-resume cycle in parallel.
++ */
++public class ContinuationTest7 {
++
++    public static void main(String[] args) throws Exception {
++        final int parallel = 2;
++        final CountDownLatch latch = new CountDownLatch(parallel);
++        for(int i = 0; i < parallel; ++i) {
++            Runnable r = new Runnable() {
++                public void run() {
++                    // Repeat the save-resume cycle 5 times
++                    for (int i = 0; i < 5; ++i) {
++                        ContinuationTestBase.gammon2(100);
++                    }
++                    latch.countDown();
++                }};
++            ContinuationTestBase.saveResumeCycle(r, null);
++        }
++        latch.await();
++        ContinuationTestBase.executor.shutdown();
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest8.java b/test/sun/misc/Continuation/ContinuationTest8.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest8.java
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++import java.util.concurrent.CountDownLatch;
++
++/*
++ * Like ContinuationTest7 but with extra stack frames via recursion.
++ */
++public class ContinuationTest8 {
++
++    public static void main(String[] args) throws Exception {
++        final int parallel = 3000;
++        final CountDownLatch latch = new CountDownLatch(parallel);
++        for(int i = 0; i < parallel; ++i) {
++            Runnable r = new Runnable() {
++                public void run() {
++                    // Repeat the save-resume cycle 5 times
++                    for (int i = 0; i < 5; ++i) {
++                        ContinuationTestBase.gammon4(100);
++                    }
++                    latch.countDown();
++                }};
++            ContinuationTestBase.saveResumeCycle(r, null);
++        }
++        latch.await();
++        ContinuationTestBase.executor.shutdown();
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTest9.java b/test/sun/misc/Continuation/ContinuationTest9.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTest9.java
+@@ -0,0 +1,180 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import java.util.LinkedList;
++import sun.misc.Continuation;
++
++/*
++ * This class demonstrates the continuation feature by implementing a
++ * user-thread-like object.
++ */
++public class ContinuationTest9 {
++    private static int ITER = 10000;
++
++    public static void test() throws Exception {
++        Runnable r1 = new Runnable() {
++            public void run() {
++                while (true) {
++                    System.out.println("t1: " + counter++);
++                    UserThread.yield();
++                    if (counter > ITER) {
++                        return;
++                    }
++                }
++            }};
++        Runnable r2 = new Runnable() {
++        public void run() {
++            while (true) {
++                System.out.println("t2: " + counter++);
++                UserThread.yield();
++                if (counter > ITER) {
++                    return;
++                }
++            }
++        }};
++        UserThread t1 = new UserThread(r1);
++        UserThread t2 = new UserThread(r2);
++        t1.start();
++        t2.start();
++        UserThread.join();
++    }
++
++    private static int counter = 0;
++
++    public static void main(String[] args) throws Exception {
++      test();
++      System.exit(0);
++    }
++}
++
++class UserThread {
++    // The schedule queue
++    private static final LinkedList<UserThread> queue = new LinkedList<UserThread>();
++    // The currently scheduled UserThread
++    private static UserThread currentThread;
++    // Used to synchronize between the internal thread and the outside world
++    // This guards queue, nthreads and currentThread
++    private static final Object lock = new Object();
++    // The number of live UserThreads
++    private static int nthreads = 0;
++    // Lock for join
++    private static final Object awaitLock = new Object();
++
++    // The backing Java thread that executes
++    // all UserThreads
++    private static final Thread jthread =
++        new Thread(new Runnable() {
++            public void run() {
++                while (true) {
++                    try {
++                        UserThread ut_to_run;
++                        synchronized (lock) {
++                            if (queue.size() == 0) {
++                                // Wait if there's no user thread to schedule
++                                lock.wait();
++                            }
++                            // Get the user thread to be scheduled next
++                            ut_to_run = queue.remove();
++                            currentThread = ut_to_run;
++                        }
++                        final UserThread ut = ut_to_run;
++                        final Continuation c = ut.continuation;
++                        // If it's scheduled for the first time,
++                        if (c == null) {
++                            // simply execute the given Runnable in a scope
++                            Continuation.enter(ut.runnable, null);
++                        } else {
++                            // Otherwise, resume the saved continuation
++                            Runnable r = new Runnable() {
++                                public void run() {
++                                    c.resume(null);
++                                }};
++                            Continuation.enter(r, null);
++                        }
++                    } catch (Throwable t) {
++                        throw new RuntimeException(t);
++                    }
++                }
++            }
++          });
++
++    static {
++        jthread.start();
++    }
++
++    private final Runnable runnable;
++    private Continuation continuation;
++
++    public UserThread(final Runnable r) {
++        runnable = new Runnable() {
++            public void run() {
++                r.run();
++                UserThread.exit();
++            }
++          };
++    }
++
++    public void start() {
++        synchronized(lock) {
++            nthreads++;
++            // Add the given user thread to the schedule queue
++            queue.add(this);
++            // Notify the Java thread if it's waiting
++            lock.notify();
++        }
++    }
++
++    public static void yield() {
++        // Create a new continuation for each yield
++        final Continuation c = new Continuation();
++        synchronized (lock) {
++            // Save it in the user thread
++            currentThread.continuation = c;
++            // Put the user thread back to the schedule queue
++            queue.add(currentThread);
++        }
++        // Save the current scope into it. It will cause
++        // the enter at the bottom of the scope to return.
++        c.save();
++    }
++
++    private static void exit() {
++        int new_nthreads;
++        synchronized (lock) {
++            nthreads--;
++            new_nthreads = nthreads;
++            if (new_nthreads == 0) {
++                synchronized (awaitLock) {
++                    awaitLock.notify();
++                }
++            }
++        }
++    }
++
++    public static void join() throws InterruptedException {
++        synchronized (awaitLock) {
++            awaitLock.wait();
++        }
++    }
++}
+diff --git a/test/sun/misc/Continuation/ContinuationTestBase.java b/test/sun/misc/Continuation/ContinuationTestBase.java
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/ContinuationTestBase.java
+@@ -0,0 +1,225 @@
++/*
++ * Copyright 2010 Google, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++import sun.misc.Continuation;
++import java.util.*;
++import java.util.concurrent.*;
++
++/*
++ * Shared code among the continuation tests.
++ */
++public class ContinuationTestBase {
++
++    static class A {
++        static int f = 0;
++    }
++
++    static String gammon1() {
++        String normally = "";
++        try {
++            System.out.println("ENTER gammon1");
++            String res = "gammon1+"+spinach(true);
++            normally = " NORMALLY";
++            return res;
++        } finally {
++            System.out.println("EXIT gammon1"+normally);
++        }
++    }
++
++    static String gammon2(final int iter) {
++        String normally = "";
++        try {
++            System.out.println("ENTER gammon2");
++            int s = 0;
++            String str = "";
++            for (int i = 0; i < iter; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++            String res = "gammon2+" + spinach(true);
++            System.out.println("after spinach.");
++            s = 0;
++            str = "";
++            for (int i = 0; i < iter; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++             normally = " NORMALLY" + str.hashCode();
++            return res;
++        } finally {
++            System.out.println("EXIT gammon2" + normally);
++        }
++    }
++
++    static String gammon3(boolean doSave) {
++        String normally = "";
++        try {
++            System.out.println("ENTER gammon3");
++            int s = 0;
++            String str = "";
++            for (int i = 0; i < 65000; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++            String res = "gammon3+" + spinach(doSave);
++            System.out.println("after spinach.");
++            s = doSave ? 0 : A.f; // induce deopt when doSave = false
++            str = "";
++            for (int i = 0; i < 65000; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++            normally = " NORMALLY" + str.hashCode();
++            return res;
++        } finally {
++            System.out.println("EXIT gammon3"+normally);
++        }
++    }
++
++    static String gammon4(final int iter) {
++        String normally = "";
++        try {
++            System.out.println("ENTER gammon4");
++            int s = 0;
++            String str = "";
++            for (int i = 0; i < iter; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++            String res = "gammon4+" + spinach2(true);
++            System.out.println("after spinach2.");
++            s = 0;
++            str = "";
++            for (int i = 0; i < iter; ++i) {
++                s = s ^ (i << 32) % 344;
++                if (s % 1000 == 0) {
++                    str += s;
++                }
++                if (i % 1000 == 0) {
++                    System.out.print(".");
++                }
++            }
++            normally = " NORMALLY" + str.hashCode();
++            return res;
++        } finally {
++            System.out.println("EXIT gammon4" + normally);
++        }
++    }
++
++    static String spinach(boolean doSave) {
++        String normally = "";
++        try {
++            System.out.println("ENTER spinach");
++            String res = "spinach+" + magic(doSave);
++            System.out.println("after magic.");
++            normally = " NORMALLY";
++            return res;
++        } finally {
++            System.out.println("EXIT spinach" + normally);
++        }
++    }
++
++    static String spinach2(boolean doSave) {
++        String normally = "";
++        try {
++            System.out.println("ENTER spinach2");
++            String res = "spinach2+" + recurse(doSave, 200);
++            System.out.println("after magic.");
++            normally = " NORMALLY";
++            return res;
++        } finally {
++            System.out.println("EXIT spinach" + normally);
++        }
++    }
++
++    static String recurse(boolean doSave, int n) {
++        if (n != 0) {
++            return recurse(doSave, n - 1);
++        }
++        return magic(doSave);
++    }
++
++    static String magic(boolean doSave) {
++        if (!doSave) {
++            return "deopt";
++        }
++        Continuation cont = new Continuation();
++        Object rv = cont.save();
++        System.out.println("Just resumed.");
++        rv = toString(rv);
++        System.out.println("save rv="+rv);
++        return rv.toString();
++    }
++
++    static String toString(Object x) {
++        if (x == null)  return "null";
++        if (x instanceof Object[])
++            return Arrays.deepToString((Object[])x);
++        return x.toString();
++    }
++
++    static ExecutorService executor = Executors.newFixedThreadPool(2);
++
++    // A helper for repeating the save-resume cycle
++    static void saveResumeCycle(final Runnable task,
++                                final Object return_value) {
++        Runnable r = new Runnable() {
++            public void run() {
++                final Continuation c = (Continuation) Continuation.enter(task, executor);
++                if (c != null) {
++                    Runnable resumer = new Runnable() {
++                        public void run() {
++                            c.resume(return_value);
++                        }};
++                    saveResumeCycle(resumer, return_value);
++                }
++            }};
++        executor.execute(r);
++    }
++}
+diff --git a/test/sun/misc/Continuation/run_all_tests.sh b/test/sun/misc/Continuation/run_all_tests.sh
+new file mode 100644
+--- /dev/null
++++ b/test/sun/misc/Continuation/run_all_tests.sh
+@@ -0,0 +1,37 @@
++#!/bin/sh
++#
++# Run all the continuation tests with different combinations of the compilers and GCs.
++
++if [ -z $JAVABIN ]
++then
++  echo "JAVABIN is unset. Set it to the java launcher. Abort."
++  exit -1
++fi
++
++DATE=`date +'%F_%T' | sed 's/\-/_/g' | sed 's/\:/_/g'`
++
++COMMON_JVM_FLAGS=""
++JVM_FLAGS_LIST="-Xint -client -server -client_-Xcomp -server_-Xcomp -server_-XX:+UseParallelGC -server_-XX:+UseConcMarkSweepGC -client_-XX:+UseParallelGC -client_-XX:+UseConcMarkSweepGC"
++
++mkdir -p logs
++mkdir -p logs/$DATE
++NTESTS=9
++
++for i in `seq 1 $NTESTS`
++do
++  TEST=ContinuationTest$i
++  echo "Running $TEST..."
++  for f in $JVM_FLAGS_LIST
++  do
++    JVM_FLAGS=`echo $f | sed 's/_/ /g'`
++    JVM_FLAGS_LABEL=`echo $f | sed 's/-/_/g'`
++    for k in `seq 1 3`
++    do
++      LABEL=$TEST-$JVM_FLAGS_LABEL-$k
++      LOG=logs/$DATE/log-$LABEL.txt
++      COMMAND="$JAVABIN $COMMON_JVM_FLAGS $JVM_FLAGS $TEST"
++      echo "Executing $COMMAND"
++      $COMMAND > $LOG 2>&1 || echo "Test $LABEL failed. The log is in $LOG"
++    done
++  done
++done
--- a/series	Wed Sep 29 15:47:58 2010 -0700
+++ b/series	Thu Oct 28 15:14:50 2010 +0200
@@ -21,7 +21,8 @@
 # Keep these separate, for debugging and review:
 dyncast.patch   #+dyncast       #-/dyncast
 inti.patch      #+inti          #-/inti #-buildable
-callcc.patch    #+callcc        #+/meth #+/indy #-/callcc #-testable
+callcc_old.patch #+callcc_old   #-/callcc_old
+continuation.patch #+continuation #-/continuation #+66e5d25098bb
 tailc.patch     #+tailc         #-/tailc
 anonk.patch                     #-/anonk #+66e5d25098bb