callcc.patch
author lstadler
Sat Sep 19 01:00:55 2009 +0200 (7 weeks ago)
changeset 60 9c5f72a3578d
parent 4524d5cf342c5
permissions -rw-r--r--
callcc: new implementation
        1 diff --git a/src/share/classes/javax/stack/Continuable.java b/src/share/classes/javax/stack/Continuable.java
        2 new file mode 100644
        3 --- /dev/null
        4 +++ b/src/share/classes/javax/stack/Continuable.java
        5 @@ -0,0 +1,10 @@
        6 +package javax.stack;
        7 +
        8 +import java.lang.annotation.*;
        9 +
       10 +@Documented
       11 +@Retention(RetentionPolicy.RUNTIME)
       12 +@Target(ElementType.METHOD)
       13 +public @interface Continuable{
       14 +	ContinuableAccess value();
       15 +}
       16 diff --git a/src/share/classes/javax/stack/ContinuableAccess.java b/src/share/classes/javax/stack/ContinuableAccess.java
       17 new file mode 100644
       18 --- /dev/null
       19 +++ b/src/share/classes/javax/stack/ContinuableAccess.java
       20 @@ -0,0 +1,5 @@
       21 +package javax.stack;
       22 +
       23 +public enum ContinuableAccess {
       24 +		HIDDEN, READONLY, READWRITE
       25 +}
       26 diff --git a/src/share/classes/javax/stack/Continuation.java b/src/share/classes/javax/stack/Continuation.java
       27 new file mode 100644
       28 --- /dev/null
       29 +++ b/src/share/classes/javax/stack/Continuation.java
       30 @@ -0,0 +1,113 @@
       31 +/*
       32 + * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
       33 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       34 + *
       35 + * This code is free software; you can redistribute it and/or modify it
       36 + * under the terms of the GNU General Public License version 2 only, as
       37 + * published by the Free Software Foundation.
       38 + *
       39 + * This code is distributed in the hope that it will be useful, but WITHOUT
       40 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       41 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       42 + * version 2 for more details (a copy is included in the LICENSE file that
       43 + * accompanied this code).
       44 + *
       45 + * You should have received a copy of the GNU General Public License version
       46 + * 2 along with this work; if not, write to the Free Software Foundation,
       47 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       48 + *
       49 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       50 + * CA 95054 USA or visit www.sun.com if you need additional information or
       51 + * have any questions.
       52 + */
       53 +package javax.stack;
       54 +
       55 +/**
       56 + * @author lstadler
       57 + */
       58 +@SuppressWarnings("unused")
       59 +public class Continuation {
       60 +	private static class CONTINUATION_CAPTURED {
       61 +	}
       62 +
       63 +	public static final Object CAPTURED = CONTINUATION_CAPTURED.class;
       64 +	private Object data;
       65 +	private Thread thread;
       66 +
       67 +	private static native void registerNatives();
       68 +
       69 +	static {
       70 +		registerNatives();
       71 +	}
       72 +
       73 +	/**
       74 +	 * Saves the current thread state into the continuation object
       75 +	 * @return null if the continuation was saved or the value given to resume if it was resumed
       76 +	 */
       77 +	public final native Object save();
       78 +
       79 +	/**
       80 +	 * Restores the stack to the state that it had when the continuation was saved.
       81 +	 * @param retValue the value that the save method should return
       82 +	 */
       83 +	public final native void resume(Object retValue);
       84 +
       85 +	/**
       86 +	 * Yields to the given target continuation, passing along the current continuation
       87 +	 * @param target the continuation that will be reinstated
       88 +	 */
       89 +	@Continuable(ContinuableAccess.HIDDEN)
       90 +	public static final void yield(Continuation target) {
       91 +		Continuation c = new Continuation();
       92 +		if (c.save() == null)
       93 +			target.resume(c);
       94 +	}
       95 +
       96 +	/*
       97 +	 * This method will be called by startDelimited
       98 +	 */
       99 +	@Continuable(ContinuableAccess.HIDDEN)
      100 +	private static final Object startDelimitedInternal(DelimitedRunnable runnable, Object firstValue) {
      101 +		Continuation cont = new Continuation();
      102 +		Object ret = cont.save();
      103 +		if (ret == CAPTURED)
      104 +			runnable.run(cont, firstValue);
      105 +		return ret;
      106 +	}
      107 +
      108 +	public static final native Object startDelimited(DelimitedRunnable runnable, Object firstValue);
      109 +
      110 +	/*
      111 +	 * This method will be called by continueDelimited
      112 +	 */
      113 +	@Continuable(ContinuableAccess.HIDDEN)
      114 +	private static final Object continueDelimitedInternal(Continuation cont, Object value) {
      115 +		cont.resume(value);
      116 +		return null;
      117 +	}
      118 +
      119 +	public static final native Object continueDelimited(Continuation continuation, Object value);
      120 +
      121 +	public final native Object dump();
      122 +
      123 +	private static final native Object storeFrameObject(Object retValue);
      124 +
      125 +	private static final native void storeFrameVoid();
      126 +
      127 +	private static final native boolean storeFrameBoolean(boolean retValue);
      128 +
      129 +	private static final native byte storeFrameByte(byte retValue);
      130 +
      131 +	private static final native char storeFrameChar(char retValue);
      132 +
      133 +	private static final native short storeFrameShort(short retValue);
      134 +
      135 +	private static final native int storeFrameInt(int retValue);
      136 +
      137 +	private static final native long storeFrameLong(long retValue);
      138 +
      139 +	private static final native float storeFrameFloat(float retValue);
      140 +
      141 +	private static final native double storeFrameDouble(double retValue);
      142 +
      143 +}
      144 diff --git a/src/share/classes/javax/stack/ContinuationPermission.java b/src/share/classes/javax/stack/ContinuationPermission.java
      145 new file mode 100644
      146 --- /dev/null
      147 +++ b/src/share/classes/javax/stack/ContinuationPermission.java
      148 @@ -0,0 +1,12 @@
      149 +package javax.stack;
      150 +
      151 +import java.security.BasicPermission;
      152 +
      153 +/* name is either "resumeSecure" or "resumeUnsecure" */
      154 +public class ContinuationPermission extends BasicPermission {
      155 +	private static final long serialVersionUID = -3608714945512368738L;
      156 +
      157 +	public ContinuationPermission(String name) {
      158 +		super(name);
      159 +	}
      160 +}
      161 \ No newline at end of file
      162 diff --git a/src/share/classes/javax/stack/DelimitedRunnable.java b/src/share/classes/javax/stack/DelimitedRunnable.java
      163 new file mode 100644
      164 --- /dev/null
      165 +++ b/src/share/classes/javax/stack/DelimitedRunnable.java
      166 @@ -0,0 +1,5 @@
      167 +package javax.stack;
      168 +
      169 +public interface DelimitedRunnable {
      170 +	public void run(Continuation start, Object firstValue);
      171 +}
      172 diff --git a/src/share/classes/javax/stack/Fiber.java b/src/share/classes/javax/stack/Fiber.java
      173 new file mode 100644
      174 --- /dev/null
      175 +++ b/src/share/classes/javax/stack/Fiber.java
      176 @@ -0,0 +1,47 @@
      177 +package javax.stack;
      178 +
      179 +public abstract class Fiber {
      180 +	private Continuation returnContinuation;
      181 +	private Continuation continuation = new Continuation();
      182 +
      183 +	private class FiberRunnable implements DelimitedRunnable {
      184 +		@Continuable(ContinuableAccess.HIDDEN)
      185 +		public final void run(Continuation start, Object firstValue) {
      186 +			returnContinuation = start;
      187 +			Object lastRetValue;
      188 +			try {
      189 +				lastRetValue = generate(firstValue);
      190 +			}
      191 +			catch (RuntimeException e) {
      192 +				e.printStackTrace();
      193 +				lastRetValue = null;
      194 +			}
      195 +			returnContinuation = null;
      196 +			start.resume(lastRetValue);
      197 +		}
      198 +	}
      199 +
      200 +	@Continuable(ContinuableAccess.HIDDEN)
      201 +	protected abstract Object generate(Object firstIn);
      202 +
      203 +	@Continuable(ContinuableAccess.HIDDEN)
      204 +	protected Object yield(Object returnValue) {
      205 +		Object o = continuation.save();
      206 +		if (o == Continuation.CAPTURED)
      207 +			returnContinuation.resume(returnValue);
      208 +		return o;
      209 +	}
      210 +
      211 +	@Continuable(ContinuableAccess.HIDDEN)
      212 +	public Object resume(Object value) {
      213 +		if (returnContinuation == null)
      214 +			return Continuation.startDelimited(new FiberRunnable(), value);
      215 +		else
      216 +			return Continuation.continueDelimited(continuation, value);
      217 +	}
      218 +
      219 +	public void dump() {
      220 +		continuation.dump();
      221 +	}
      222 +
      223 +}
      224 diff --git a/test/javax/stack/ContinuationTest1.java b/test/javax/stack/ContinuationTest1.java
      225 new file mode 100644
      226 --- /dev/null
      227 +++ b/test/javax/stack/ContinuationTest1.java
      228 @@ -0,0 +1,229 @@
      229 +package javax.stack;
      230 +
      231 +import static org.junit.Assert.assertEquals;
      232 +
      233 +import org.junit.Before;
      234 +import org.junit.Test;
      235 +
      236 +public class ContinuationTest1 extends ContinuationTestTools {
      237 +
      238 +	public ContinuationTest1() {
      239 +		interpreted = this;
      240 +		if (compiled == null)
      241 +			compiled = new ContinuationTest1Compiled();
      242 +	}
      243 +
      244 +	@Before
      245 +	public void setUp() throws Exception {
      246 +		clearActions();
      247 +	}
      248 +
      249 +	@Continuable(ContinuableAccess.HIDDEN)
      250 +	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
      251 +		int i;
      252 +		cont.save();
      253 +		i = 0;
      254 +		i += a;
      255 +		i += b;
      256 +		i += c;
      257 +		i += d;
      258 +		i += e;
      259 +		assertEquals(15, i);
      260 +		assertEquals(ContinuationTest1.class, this.getClass());
      261 +		assertEquals(Continuation.class, cont.getClass());
      262 +		return 10102;
      263 +	}
      264 +
      265 +	private int cnt = 0;
      266 +
      267 +	@Test
      268 +	@Continuable(ContinuableAccess.HIDDEN)
      269 +	public void testRec() {
      270 +		Integer i = 100000;
      271 +		Continuation cont = new Continuation();
      272 +		assertEquals(10102, compiled.subSave(cont, 1, 2, 3, 4, 5));
      273 +		assertEquals(ContinuationTest1.class, this.getClass());
      274 +		if (cnt++ == 0) {
      275 +			cont.resume(null);
      276 +		}
      277 +		assertEquals(100000, i);
      278 +	}
      279 +
      280 +	@Test
      281 +	@Continuable(ContinuableAccess.HIDDEN)
      282 +	public void testSimple() {
      283 +		Continuation cont = new Continuation();
      284 +		action(1);
      285 +		if (cont.save() == Continuation.CAPTURED) {
      286 +			action(2);
      287 +			cont.resume(null);
      288 +			action(100);
      289 +		}
      290 +		else
      291 +			action(3);
      292 +
      293 +		action(4);
      294 +		assertActions(new int[] { 1, 2, 3, 4 });
      295 +	}
      296 +
      297 +	@Continuable(ContinuableAccess.HIDDEN)
      298 +	int intSub(Continuation c, int code1, Integer code2, int depth) {
      299 +		if (depth == 0) {
      300 +			action(code1);
      301 +			intTemp = code1;
      302 +			objTemp = code2;
      303 +			thisTemp = this;
      304 +			lastSaveReturn = c.save();
      305 +			action(code2);
      306 +			assertEquals(thisTemp, this);
      307 +			assertEquals(intTemp, code1);
      308 +			assertEquals(objTemp, code2);
      309 +		}
      310 +		else {
      311 +			if ((depth & 3) == 0)
      312 +				compiled.intSub(c, code1, code2, depth - 1);
      313 +			else
      314 +				intSub(c, code1, code2, depth - 1);
      315 +		}
      316 +		return 101;
      317 +	}
      318 +
      319 +	@Continuable(ContinuableAccess.HIDDEN)
      320 +	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
      321 +		if (depth == 0) {
      322 +			action(code1);
      323 +			intTemp = code1;
      324 +			objTemp = code2;
      325 +			thisTemp = this;
      326 +			lastSaveReturn = c.save();
      327 +			assertEquals(thisTemp, this);
      328 +			assertEquals(intTemp, code1);
      329 +			assertEquals(objTemp, code2);
      330 +			action(code2);
      331 +		}
      332 +		else {
      333 +			if ((depth & 3) == 0)
      334 +				compiled.objSub(c, code1, code2, depth - 1);
      335 +			else
      336 +				objSub(c, code1, code2, depth - 1);
      337 +		}
      338 +		return 201;
      339 +	}
      340 +
      341 +	@Continuable(ContinuableAccess.HIDDEN)
      342 +	void resumeRec(Continuation c, Object retValue, int depth) {
      343 +		if (depth == 0) {
      344 +			c.resume(null);
      345 +		}
      346 +		else {
      347 +			if ((depth & 3) == 0)
      348 +				compiled.resumeRec(c, retValue, depth - 1);
      349 +			else
      350 +				resumeRec(c, retValue, depth - 1);
      351 +		}
      352 +	}
      353 +
      354 +	@Continuable(ContinuableAccess.HIDDEN)
      355 +	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
      356 +		Continuation c = new Continuation();
      357 +		action(1);
      358 +		action(intSub(c, 2, 3, saveDepth));
      359 +		if (lastSaveReturn == Continuation.CAPTURED) {
      360 +			action(4);
      361 +			if (resumeDepth == 0)
      362 +				c.resume(null);
      363 +			else
      364 +				resumeRec(c, null, resumeDepth);
      365 +			action(100);
      366 +		}
      367 +		action(5);
      368 +		action(compiled.intSub(c, 6, 7, saveDepth));
      369 +		if (lastSaveReturn == Continuation.CAPTURED) {
      370 +			action(8);
      371 +			if (resumeDepth == 0)
      372 +				c.resume(null);
      373 +			else
      374 +				resumeRec(c, null, resumeDepth);
      375 +			action(100);
      376 +		}
      377 +		action(9);
      378 +		action(objSub(c, 10, 11, saveDepth));
      379 +		if (lastSaveReturn == Continuation.CAPTURED) {
      380 +			action(12);
      381 +			if (resumeDepth == 0)
      382 +				c.resume(null);
      383 +			else
      384 +				resumeRec(c, null, resumeDepth);
      385 +			action(100);
      386 +		}
      387 +		action(13);
      388 +		action(compiled.objSub(c, 14, 15, saveDepth));
      389 +		if (lastSaveReturn == Continuation.CAPTURED) {
      390 +			action(16);
      391 +			if (resumeDepth == 0)
      392 +				c.resume(null);
      393 +			else
      394 +				resumeRec(c, null, resumeDepth);
      395 +			action(100);
      396 +		}
      397 +		action(17);
      398 +		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,
      399 +				16, 15, 202, 17 });
      400 +	}
      401 +
      402 +	@Test
      403 +	public void testParamsReturn() {
      404 +		for (int i2 = 1; i2 < 50; i2++) {
      405 +			for (int i = 0; i < 50; i++) {
      406 +//				System.out.println("resume: " + i + ", save: " + i2);
      407 +				pushActions();
      408 +				testParamsReturnInternal(i, i2);
      409 +				popActions();
      410 +			}
      411 +		}
      412 +	}
      413 +
      414 +	@Test
      415 +	@Continuable(ContinuableAccess.HIDDEN)
      416 +	public void testManyParams() {
      417 +		Continuation cont = new Continuation();
      418 +		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
      419 +				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
      420 +			cont.resume(null);
      421 +	}
      422 +
      423 +	@Continuable(ContinuableAccess.HIDDEN)
      424 +	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f,
      425 +			long g, Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r,
      426 +			int s, int t, int u, int v) {
      427 +		final Object ret;
      428 +		if (depth > 0)
      429 +			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);
      430 +		else
      431 +			ret = cont.save();
      432 +		assertEquals(cont.getClass(), Continuation.class);
      433 +		assertEquals(a, true);
      434 +		assertEquals(b, false);
      435 +		assertEquals(c, 1);
      436 +		assertEquals(d, (short) 2);
      437 +		assertEquals(e, (byte) 3);
      438 +		assertEquals(f, (char) 4);
      439 +		assertEquals(g, (long) 5);
      440 +		assertEquals(h, 6);
      441 +		assertEquals(i, (short) 7);
      442 +		assertEquals(j, (byte) 8);
      443 +		assertEquals(k, (char) 9);
      444 +		assertEquals(l, (long) 10);
      445 +		assertEquals(m, (float) 11);
      446 +		assertEquals(n, (double) 12);
      447 +		assertEquals(o, (float) 13);
      448 +		assertEquals(p, (double) 14);
      449 +		assertEquals(q, 15);
      450 +		assertEquals(r, 16);
      451 +		assertEquals(s, 17);
      452 +		assertEquals(t, 18);
      453 +		assertEquals(u, 19);
      454 +		assertEquals(v, 20);
      455 +		return ret;
      456 +	}
      457 +}
      458 diff --git a/test/javax/stack/ContinuationTest1Compiled.java b/test/javax/stack/ContinuationTest1Compiled.java
      459 new file mode 100644
      460 --- /dev/null
      461 +++ b/test/javax/stack/ContinuationTest1Compiled.java
      462 @@ -0,0 +1,225 @@
      463 +package javax.stack;
      464 +
      465 +import static org.junit.Assert.assertEquals;
      466 +
      467 +import org.junit.Before;
      468 +import org.junit.Test;
      469 +
      470 +public class ContinuationTest1Compiled extends ContinuationTestTools {
      471 +
      472 +	public ContinuationTest1Compiled() {
      473 +		compiled = this;
      474 +		if (interpreted == null)
      475 +			interpreted = new ContinuationTest1();
      476 +	}
      477 +
      478 +	@Before
      479 +	public void setUp() throws Exception {
      480 +		clearActions();
      481 +	}
      482 +
      483 +	@Continuable(ContinuableAccess.HIDDEN)
      484 +	public Object subSave(Continuation cont, int a, int b, int c, int d, int e) {
      485 +		int i;
      486 +		cont.save();
      487 +		i = 0;
      488 +		i += a;
      489 +		i += b;
      490 +		i += c;
      491 +		i += d;
      492 +		i += e;
      493 +		assertEquals(15, i);
      494 +		assertEquals(ContinuationTest1Compiled.class, this.getClass());
      495 +		assertEquals(Continuation.class, cont.getClass());
      496 +		return 10102;
      497 +	}
      498 +
      499 +	private int cnt = 0;
      500 +
      501 +	@Test
      502 +	@Continuable(ContinuableAccess.HIDDEN)
      503 +	public void testRec() {
      504 +		Integer i = 100000;
      505 +		Continuation cont = new Continuation();
      506 +		assertEquals(10102, interpreted.subSave(cont, 1, 2, 3, 4, 5));
      507 +		assertEquals(ContinuationTest1Compiled.class, this.getClass());
      508 +		if (cnt++ == 0)
      509 +			cont.resume(null);
      510 +		assertEquals(100000, i);
      511 +	}
      512 +
      513 +	@Test
      514 +	@Continuable(ContinuableAccess.HIDDEN)
      515 +	public void testSimple() {
      516 +		Continuation cont = new Continuation();
      517 +		action(1);
      518 +		if (cont.save() == Continuation.CAPTURED) {
      519 +			action(2);
      520 +			cont.resume(null);
      521 +			action(100);
      522 +		}
      523 +		else
      524 +			action(3);
      525 +
      526 +		action(4);
      527 +		assertActions(new int[] { 1, 2, 3, 4 });
      528 +	}
      529 +
      530 +	@Continuable(ContinuableAccess.HIDDEN)
      531 +	int intSub(Continuation c, int code1, Integer code2, int depth) {
      532 +		if (depth == 0) {
      533 +			action(code1);
      534 +			intTemp = code1;
      535 +			objTemp = code2;
      536 +			lastSaveReturn = c.save();
      537 +			assertEquals(intTemp, code1);
      538 +			assertEquals(objTemp, code2);
      539 +			action(code2);
      540 +		}
      541 +		else {
      542 +			if ((depth & 3) == 0)
      543 +				interpreted.intSub(c, code1, code2, depth - 1);
      544 +			else
      545 +				intSub(c, code1, code2, depth - 1);
      546 +		}
      547 +		return 102;
      548 +	}
      549 +
      550 +	@Continuable(ContinuableAccess.HIDDEN)
      551 +	Integer objSub(Continuation c, int code1, Integer code2, int depth) {
      552 +		if (depth == 0) {
      553 +			action(code1);
      554 +			intTemp = code1;
      555 +			objTemp = code2;
      556 +			lastSaveReturn = c.save();
      557 +			assertEquals(intTemp, code1);
      558 +			assertEquals(objTemp, code2);
      559 +			action(code2);
      560 +		}
      561 +		else {
      562 +			if ((depth & 3) == 0)
      563 +				interpreted.objSub(c, code1, code2, depth - 1);
      564 +			else
      565 +				objSub(c, code1, code2, depth - 1);
      566 +		}
      567 +		return 202;
      568 +	}
      569 +
      570 +	@Continuable(ContinuableAccess.HIDDEN)
      571 +	void resumeRec(Continuation c, Object retValue, int depth) {
      572 +		if (depth == 0) {
      573 +			c.resume(null);
      574 +		}
      575 +		else {
      576 +			if ((depth & 3) == 0)
      577 +				interpreted.resumeRec(c, retValue, depth - 1);
      578 +			else
      579 +				resumeRec(c, retValue, depth - 1);
      580 +		}
      581 +	}
      582 +
      583 +	@Continuable(ContinuableAccess.HIDDEN)
      584 +	public void testParamsReturnInternal(int resumeDepth, int saveDepth) {
      585 +		Continuation c = new Continuation();
      586 +		action(1);
      587 +		action(interpreted.intSub(c, 2, 3, saveDepth));
      588 +		if (lastSaveReturn == Continuation.CAPTURED) {
      589 +			action(4);
      590 +			if (resumeDepth == 0)
      591 +				c.resume(null);
      592 +			else
      593 +				resumeRec(c, null, resumeDepth);
      594 +			action(100);
      595 +		}
      596 +		action(5);
      597 +		action(intSub(c, 6, 7, saveDepth));
      598 +		if (lastSaveReturn == Continuation.CAPTURED) {
      599 +			action(8);
      600 +			if (resumeDepth == 0)
      601 +				c.resume(null);
      602 +			else
      603 +				resumeRec(c, null, resumeDepth);
      604 +			action(100);
      605 +		}
      606 +		action(9);
      607 +		action(interpreted.objSub(c, 10, 11, saveDepth));
      608 +		if (lastSaveReturn == Continuation.CAPTURED) {
      609 +			action(12);
      610 +			if (resumeDepth == 0)
      611 +				c.resume(null);
      612 +			else
      613 +				resumeRec(c, null, resumeDepth);
      614 +			action(100);
      615 +		}
      616 +		action(13);
      617 +		action(objSub(c, 14, 15, saveDepth));
      618 +		if (lastSaveReturn == Continuation.CAPTURED) {
      619 +			action(16);
      620 +			if (resumeDepth == 0)
      621 +				c.resume(null);
      622 +			else
      623 +				resumeRec(c, null, resumeDepth);
      624 +			action(100);
      625 +		}
      626 +		action(17);
      627 +		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,
      628 +				16, 15, 202, 17 });
      629 +	}
      630 +
      631 +	@Test
      632 +	public void testParamsReturn() {
      633 +		for (int i2 = 0; i2 < 50; i2++) {
      634 +			for (int i = 0; i < 50; i++) {
      635 +				// System.out.println("resume: " + i + ", save: " + i2);
      636 +				pushActions();
      637 +				testParamsReturnInternal(i, i2);
      638 +				popActions();
      639 +			}
      640 +		}
      641 +	}
      642 +
      643 +	@Test
      644 +	@Continuable(ContinuableAccess.HIDDEN)
      645 +	public void testManyParams() {
      646 +		Continuation cont = new Continuation();
      647 +		if (manyParamsSub(cont, 5, true, false, 1, (short) 2, (byte) 3, (char) 4, (long) 5, 6, (short) 7, (byte) 8, (char) 9,
      648 +				(long) 10, (float) 11, (double) 12, (float) 13, (double) 14, 15, 16, 17, 18, 19, 20) == Continuation.CAPTURED)
      649 +			cont.resume(null);
      650 +	}
      651 +
      652 +	@Continuable(ContinuableAccess.HIDDEN)
      653 +	private Object manyParamsSub(Continuation cont, int depth, boolean a, boolean b, int c, short d, byte e, char f, long g,
      654 +			Integer h, Short i, Byte j, Character k, Long l, float m, double n, Float o, Double p, Integer q, int r, int s,
      655 +			int t, int u, int v) {
      656 +		final Object ret;
      657 +		if (depth > 0)
      658 +			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);
      659 +		else
      660 +			ret = cont.save();
      661 +		assertEquals(cont.getClass(), Continuation.class);
      662 +		assertEquals(a, true);
      663 +		assertEquals(b, false);
      664 +		assertEquals(c, 1);
      665 +		assertEquals(d, (short) 2);
      666 +		assertEquals(e, (byte) 3);
      667 +		assertEquals(f, (char) 4);
      668 +		assertEquals(g, (long) 5);
      669 +		assertEquals(h, 6);
      670 +		assertEquals(i, (short) 7);
      671 +		assertEquals(j, (byte) 8);
      672 +		assertEquals(k, (char) 9);
      673 +		assertEquals(l, (long) 10);
      674 +		assertEquals(m, (float) 11);
      675 +		assertEquals(n, (double) 12);
      676 +		assertEquals(o, (float) 13);
      677 +		assertEquals(p, (double) 14);
      678 +		assertEquals(q, 15);
      679 +		assertEquals(r, 16);
      680 +		assertEquals(s, 17);
      681 +		assertEquals(t, 18);
      682 +		assertEquals(u, 19);
      683 +		assertEquals(v, 20);
      684 +		return ret;
      685 +	}
      686 +
      687 +}
      688 diff --git a/test/javax/stack/ContinuationTestTools.java b/test/javax/stack/ContinuationTestTools.java
      689 new file mode 100644
      690 --- /dev/null
      691 +++ b/test/javax/stack/ContinuationTestTools.java
      692 @@ -0,0 +1,53 @@
      693 +package javax.stack;
      694 +
      695 +import static org.junit.Assert.assertEquals;
      696 +
      697 +import java.util.ArrayList;
      698 +import java.util.Stack;
      699 +
      700 +public class ContinuationTestTools {
      701 +	private static Stack<ArrayList<Integer>> actions = new Stack<ArrayList<Integer>>();
      702 +
      703 +	protected static Object thisTemp;
      704 +	protected static Object objTemp;
      705 +	protected static int intTemp;
      706 +	protected static Object lastSaveReturn = null;
      707 +
      708 +	protected static ContinuationTest1Compiled compiled;
      709 +	protected static ContinuationTest1 interpreted;
      710 +
      711 +	protected static void clearActions() {
      712 +		actions.clear();
      713 +		actions.add(new ArrayList<Integer>());
      714 +	}
      715 +
      716 +	protected static void pushActions() {
      717 +		actions.push(new ArrayList<Integer>());
      718 +	}
      719 +
      720 +	protected static void popActions() {
      721 +		actions.pop();
      722 +	}
      723 +
      724 +	protected static void action(int code) {
      725 +		actions.peek().add(code);
      726 +	}
      727 +
      728 +	protected static void assertActions(int[] expectedActions) {
      729 +		if (expectedActions.length == actions.peek().size()) {
      730 +			for (int i = 0; i < expectedActions.length; i++)
      731 +				assertEquals(expectedActions[i], actions.peek().get(i));
      732 +		}
      733 +		else {
      734 +			System.out.print("expected: ");
      735 +			for (int i = 0; i < expectedActions.length; i++)
      736 +				System.out.print(expectedActions[i] + " ");
      737 +			System.out.print("\nactual: ");
      738 +			for (int i = 0; i < actions.peek().size(); i++)
      739 +				System.out.print(actions.peek().get(i) + " ");
      740 +
      741 +			assertEquals(expectedActions.length, actions.peek().size());
      742 +		}
      743 +	}
      744 +
      745 +}
      746 diff --git a/test/javax/stack/DelimitedTest.java b/test/javax/stack/DelimitedTest.java
      747 new file mode 100644
      748 --- /dev/null
      749 +++ b/test/javax/stack/DelimitedTest.java
      750 @@ -0,0 +1,47 @@
      751 +package javax.stack;
      752 +
      753 +import java.io.IOException;
      754 +
      755 +import org.junit.Test;
      756 +
      757 +public class DelimitedTest {
      758 +
      759 +	class TestFiber extends Fiber {
      760 +		@Continuable(ContinuableAccess.HIDDEN)
      761 +		protected Object generate(Object value) {
      762 +			int i = (Integer) value;
      763 +			while (true) {
      764 +				i += (Integer) yield(i);
      765 +			}
      766 +		}
      767 +	}
      768 +
      769 +	private static final long COUNT = 5000;
      770 +	private static final long COUNT2 = 100;
      771 +
      772 +	@Test
      773 +	@Continuable(ContinuableAccess.HIDDEN)
      774 +	public void testRec() throws IOException {
      775 +		try {
      776 +			Continuation cont = new Continuation();
      777 +			cont.save();
      778 +			do {
      779 +				long time = System.nanoTime();
      780 +				for (int i2 = 0; i2 < COUNT2; i2++) {
      781 +					TestFiber test = new TestFiber();
      782 +					for (int i = 0; i < COUNT; i++) {
      783 +						Object ret = test.resume(i);
      784 +						int result = (Integer) ret;
      785 +					}
      786 +				}
      787 +				long tps = (long) (COUNT * COUNT2 * 1000000000d / (System.nanoTime() - time));
      788 +				System.out.println(tps);
      789 +			}
      790 +			while (true);
      791 +		}
      792 +		catch (Throwable e) {
      793 +			e.printStackTrace();
      794 +		}
      795 +	}
      796 +
      797 +}
      798 \ No newline at end of file