diff --git a/classpath/avian/Cell.java b/classpath/avian/Cell.java index 448c515c19..afe9c9213b 100644 --- a/classpath/avian/Cell.java +++ b/classpath/avian/Cell.java @@ -31,4 +31,24 @@ public class Cell { sb.append(")"); return sb.toString(); } + + public static Cell cons(Car car, Cell cdr) { + return new Cell(car, cdr); + } + + public static boolean equal(T a, T b) { + return (a == null && b == null) || (a != null && a.equals(b)); + } + + public static boolean equal(Cell a, Cell b) { + while (a != null) { + if (b == null || (! equal(a.value, b.value))) { + return false; + } + a = a.next; + b = b.next; + } + + return b == null; + } } diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 631bd48a72..3401cbcd45 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -120,19 +120,21 @@ import java.util.concurrent.Callable; public class Continuations { private Continuations() { } + private static final ThreadLocal latestReset = new ThreadLocal(); + /** * Captures the current continuation, passing a reference to the * specified receiver. * *

This method will either return the result returned by - * receiver.receive(Callback), propagate the exception + * receiver.call(Callback), propagate the exception * thrown by that method, return the result passed to the * handleResult(T) method of the continuation, or throw the * exception passed to the handleException(Throwable) method of the * continuation. */ public static native T callWithCurrentContinuation - (CallbackReceiver receiver) throws Exception; + (Function,T> receiver) throws Exception; /** * Calls the specified "before" and "after" tasks each time a @@ -181,6 +183,83 @@ public class Continuations { } } + public static C reset(final Callable thunk) throws Exception { + final Reset reset = new Reset(latestReset.get()); + latestReset.set(reset); + try { + Object result = callWithCurrentContinuation + (new Function,Object>() { + public Object call(Callback continuation) throws Exception { + reset.continuation = continuation; + return thunk.call(); + } + }); + + while (true) { + Cell shift = reset.shifts; + if (shift != null) { + reset.shifts = shift.next; + result = shift.value.call(result); + } else { + return (C) result; + } + } + } finally { + latestReset.set(reset.next); + } + } + + public static A shift + (final Function,C> receiver) + throws Exception + { + return (A) callWithCurrentContinuation + (new Function,Object>() { + public Object call(final Callback continuation) { + final Reset reset = latestReset.get(); + reset.shifts = new Cell(new Function() { + public Object call(Object ignored) throws Exception { + return receiver.call + (new Function() { + public Object call(final Object argument) + throws Exception + { + return callWithCurrentContinuation + (new Function,Object>() { + public Object call + (final Callback shiftContinuation) + throws Exception + { + reset.shifts = new Cell + (new Function() { + public Object call(Object result) + throws Exception + { + shiftContinuation.handleResult(result); + throw new AssertionError(); + } + }, + reset.shifts); + + continuation.handleResult(argument); + throw new AssertionError(); + } + }); + } + }); + } + + public void handleException(Throwable exception) { + throw new AssertionError(); + } + }, reset.shifts); + + reset.continuation.handleResult(null); + throw new AssertionError(); + } + }); + } + private static native UnwindResult dynamicWind2(Runnable before, Callable thunk, Runnable after) @@ -235,4 +314,14 @@ public class Continuations { this.exception = exception; } } + + private static class Reset { + public Callback continuation; + public final Reset next; + public Cell shifts; + + public Reset(Reset next) { + this.next = next; + } + } } diff --git a/classpath/avian/CallbackReceiver.java b/classpath/avian/Function.java similarity index 79% rename from classpath/avian/CallbackReceiver.java rename to classpath/avian/Function.java index 82c54fba20..8d42f7b193 100644 --- a/classpath/avian/CallbackReceiver.java +++ b/classpath/avian/Function.java @@ -10,6 +10,6 @@ package avian; -public interface CallbackReceiver { - public T receive(Callback callback) throws Exception; +public interface Function { + public B call(A argument) throws Exception; } diff --git a/makefile b/makefile index fce13ac081..f4be56d570 100755 --- a/makefile +++ b/makefile @@ -192,7 +192,7 @@ ifneq ($(android),) crypto-native := $(android)/libcore/crypto/src/main/native ifeq ($(platform),windows) - crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp + crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp android-cflags += -D__STDC_CONSTANT_MACROS blacklist = $(luni-native)/java_io_Console.cpp \ $(luni-native)/java_lang_ProcessManager.cpp \ @@ -1330,13 +1330,13 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/AnnotationInvocationHandler.java \ $(classpath-src)/avian/Assembler.java \ $(classpath-src)/avian/Callback.java \ - $(classpath-src)/avian/CallbackReceiver.java \ $(classpath-src)/avian/ClassAddendum.java \ $(classpath-src)/avian/InnerClassReference.java \ $(classpath-src)/avian/Classes.java \ $(classpath-src)/avian/ConstantPool.java \ $(classpath-src)/avian/Continuations.java \ $(classpath-src)/avian/FieldAddendum.java \ + $(classpath-src)/avian/Function.java \ $(classpath-src)/avian/IncompatibleContinuationException.java \ $(classpath-src)/avian/Machine.java \ $(classpath-src)/avian/MethodAddendum.java \ @@ -1397,6 +1397,7 @@ unittest-depends = \ ifeq ($(continuations),true) continuation-tests = \ + extra.ComposableContinuations \ extra.Continuations \ extra.Coroutines \ extra.DynamicWind diff --git a/src/compile.cpp b/src/compile.cpp index 41e63823cd..b974567f4b 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8044,8 +8044,8 @@ callWithCurrentContinuation(MyThread* t, object receiver) if (root(t, ReceiveMethod) == 0) { object m = resolveMethod - (t, root(t, Machine::BootLoader), "avian/CallbackReceiver", "receive", - "(Lavian/Callback;)Ljava/lang/Object;"); + (t, root(t, Machine::BootLoader), "avian/Function", "call", + "(Ljava/lang/Object;)Ljava/lang/Object;"); if (m) { setRoot(t, ReceiveMethod, m); diff --git a/src/types.def b/src/types.def index 7bb8bc1fb0..82b0e5a5aa 100644 --- a/src/types.def +++ b/src/types.def @@ -176,8 +176,6 @@ (type unwindResult avian/Continuations$UnwindResult) -(type callbackReceiver avian/CallbackReceiver) - (type string java/lang/String (alias data object value) (alias length uint32_t count) diff --git a/test/extra/ComposableContinuations.java b/test/extra/ComposableContinuations.java new file mode 100644 index 0000000000..d33d39693b --- /dev/null +++ b/test/extra/ComposableContinuations.java @@ -0,0 +1,93 @@ +package extra; + +import static avian.Continuations.shift; +import static avian.Cell.cons; +import static avian.Cell.equal; + +import avian.Cell; +import avian.Function; +import avian.Continuations; + +import java.util.concurrent.Callable; + +public class ComposableContinuations { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + public static void main(String[] args) throws Exception { + expect(2 * Continuations.reset(new Callable() { + public Integer call() throws Exception { + return 1 + shift + (new Function,Integer>() { + public Integer call(Function continuation) + throws Exception + { + return continuation.call(5); + } + }); + } + }) == 12); + + expect(1 + Continuations.reset(new Callable() { + public Integer call() throws Exception { + return 2 * shift + (new Function,Integer>() { + public Integer call(Function continuation) + throws Exception + { + return continuation.call(continuation.call(4)); + } + }); + } + }) == 17); + + expect + (equal + (Continuations.,Cell>reset + (new Callable>() { + public Cell call() throws Exception { + shift(new Function,Cell>, + Cell>() + { + public Cell call + (Function,Cell> continuation) + throws Exception + { + return cons(1, continuation.call(null)); + } + }); + + shift(new Function,Cell>, + Cell>() + { + public Cell call + (Function,Cell> continuation) + throws Exception + { + return cons(2, continuation.call(null)); + } + }); + + return null; + } + }), cons(1, cons(2, null)))); + + expect + (equal + (Continuations.reset + (new Callable() { + public String call() throws Exception { + return new String + (shift(new Function,Integer>() { + public Integer call(Function continuation) + throws Exception + { + return Integer.parseInt + (continuation.call(new byte[] { 0x34, 0x32 })); + } + }), "UTF-8"); + } + }), 42)); + } +} diff --git a/test/extra/Continuations.java b/test/extra/Continuations.java index a439d8a58d..1186c43a4a 100644 --- a/test/extra/Continuations.java +++ b/test/extra/Continuations.java @@ -2,7 +2,7 @@ package extra; import static avian.Continuations.callWithCurrentContinuation; -import avian.CallbackReceiver; +import avian.Function; import avian.Callback; public class Continuations { @@ -11,22 +11,26 @@ public class Continuations { } public static void main(String[] args) throws Exception { - expect(callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) { - continuation.handleResult(42); - throw new AssertionError(); - } - }) == 42); + expect + (callWithCurrentContinuation + (new Function,Integer>() { + public Integer call(Callback continuation) { + continuation.handleResult(42); + throw new AssertionError(); + } + }) == 42); - expect(callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) { - return 43; - } - }) == 43); + expect + (callWithCurrentContinuation + (new Function,Integer>() { + public Integer call(Callback continuation) { + return 43; + } + }) == 43); try { - callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) { + callWithCurrentContinuation(new Function,Integer>() { + public Integer call(Callback continuation) { continuation.handleException(new MyException()); throw new AssertionError(); } @@ -37,8 +41,8 @@ public class Continuations { } try { - callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) + callWithCurrentContinuation(new Function,Integer>() { + public Integer call(Callback continuation) throws MyException { throw new MyException(); diff --git a/test/extra/Coroutines.java b/test/extra/Coroutines.java index 7d4ee9c5a5..3afd2dce73 100644 --- a/test/extra/Coroutines.java +++ b/test/extra/Coroutines.java @@ -2,7 +2,7 @@ package extra; import static avian.Continuations.callWithCurrentContinuation; -import avian.CallbackReceiver; +import avian.Function; import avian.Callback; public class Coroutines { @@ -40,8 +40,8 @@ public class Coroutines { final Consumer consumer = new Consumer() { public void consume(final Character c) throws Exception { - callWithCurrentContinuation(new CallbackReceiver() { - public Object receive(Callback continuation) { + callWithCurrentContinuation(new Function,Object>() { + public Object call(Callback continuation) { state.produceNext = continuation; state.consumeNext.handleResult(c); @@ -53,9 +53,9 @@ public class Coroutines { }; final Producer producer = new Producer() { - final CallbackReceiver receiver - = new CallbackReceiver() { - public Character receive(Callback continuation) + final Function,Character> receiver + = new Function,Character>() { + public Character call(Callback continuation) throws Exception { state.consumeNext = continuation; diff --git a/test/extra/DynamicWind.java b/test/extra/DynamicWind.java index aa617ddc9c..bbc305842c 100644 --- a/test/extra/DynamicWind.java +++ b/test/extra/DynamicWind.java @@ -3,7 +3,7 @@ package extra; import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.dynamicWind; -import avian.CallbackReceiver; +import avian.Function; import avian.Callback; import java.util.concurrent.Callable; @@ -86,24 +86,27 @@ public class DynamicWind { }); } - private void continuationUnwindTest(final CallbackReceiver receiver) + private void continuationUnwindTest + (final Function,Integer> receiver) throws Exception { System.out.println("continuationUnwindTest enter"); try { - expect(callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(final Callback continuation) - throws Exception - { - unwindTest(new Callable() { - public Integer call() throws Exception { - return receiver.receive(continuation); - } - }); - throw new AssertionError(); - } - }) == 42); + expect + (callWithCurrentContinuation + (new Function,Integer>() { + public Integer call(final Callback continuation) + throws Exception + { + unwindTest(new Callable() { + public Integer call() throws Exception { + return receiver.call(continuation); + } + }); + throw new AssertionError(); + } + }) == 42); } catch (MyException e) { e.printStackTrace(); } @@ -118,8 +121,8 @@ public class DynamicWind { } private void continuationResultUnwind() throws Exception { - continuationUnwindTest(new CallbackReceiver() { - public Integer receive(final Callback continuation) { + continuationUnwindTest(new Function,Integer>() { + public Integer call(final Callback continuation) { continuation.handleResult(42); throw new AssertionError(); } @@ -127,8 +130,8 @@ public class DynamicWind { } private void continuationExceptionUnwind() throws Exception { - continuationUnwindTest(new CallbackReceiver() { - public Integer receive(final Callback continuation) { + continuationUnwindTest(new Function,Integer>() { + public Integer call(final Callback continuation) { continuation.handleException(new MyException()); throw new AssertionError(); } @@ -163,8 +166,8 @@ public class DynamicWind { task = 1; return callWithCurrentContinuation - (new CallbackReceiver() { - public Integer receive(final Callback continuation) + (new Function,Integer>() { + public Integer call(final Callback continuation) throws Exception { continuationReference = continuation; diff --git a/test/test.sh b/test/test.sh index b56dcbb436..0bd3db7d68 100644 --- a/test/test.sh +++ b/test/test.sh @@ -18,7 +18,7 @@ fi echo -n "" >${log} -printf "%12s------- Unit tests -------\n" "" +printf "%20s------- Unit tests -------\n" "" ${unit_tester} 2>>${log} if [ "${?}" != "0" ]; then trouble=1 @@ -27,9 +27,9 @@ fi echo -printf "%12s------- Java tests -------\n" "" +printf "%20s------- Java tests -------\n" "" for test in ${tests}; do - printf "%24s: " "${test}" + printf "%32s: " "${test}" case ${mode} in debug|debug-fast|fast|small ) diff --git a/unittest/test-harness.cpp b/unittest/test-harness.cpp index 1c11c480a3..5092501861 100644 --- a/unittest/test-harness.cpp +++ b/unittest/test-harness.cpp @@ -32,7 +32,7 @@ Test::Test(const char* name): bool Test::runAll() { int failures = 0; for(Test* t = Test::first; t; t = t->next) { - printf("%24s: ", t->name); + printf("%32s: ", t->name); t->run(); failures += t->failures; if(t->failures > 0) { @@ -49,4 +49,4 @@ int main(int argc UNUSED, char** argv UNUSED) { return 0; } return 1; -} \ No newline at end of file +}