diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 4074b28897..0953995320 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -21,27 +21,27 @@ public abstract class Continuations { Runnable after) throws Exception { - UnwindResult result = dynamicWind2(buffer, thunk, after); + UnwindResult result = dynamicWind2(before, thunk, after); if (result.continuation != null) { after.run(); if (result.exception != null) { result.continuation.handleException(result.exception); } else { - result.continuation.handleResult(result.value); + result.continuation.handleResult(result.result); } throw new AssertionError(); } else { - return (T) result.value; + return (T) result.result; } } private static native UnwindResult dynamicWind2(Runnable before, - Callable thunk, + Callable thunk, Runnable after) throws Exception; private static UnwindResult wind(Runnable before, - Callable thunk, + Callable thunk, Runnable after) throws Exception { @@ -65,7 +65,7 @@ public abstract class Continuations { if (exception != null) { continuation.handleException(exception); } else { - continuation.handleResult(value); + continuation.handleResult(result); } throw new AssertionError(); diff --git a/src/compile.cpp b/src/compile.cpp index 9018808673..8ae1b2c020 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -49,13 +49,14 @@ class MyThread: public Thread { public: class CallTrace { public: - CallTrace(MyThread* t): + CallTrace(MyThread* t, object method): t(t), base(t->base), stack(t->stack), continuation(t->continuation), - nativeMethod(0), + nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0), targetMethod(0), + originalMethod(method), next(t->trace) { t->trace = this; @@ -77,6 +78,7 @@ class MyThread: public Thread { object continuation; object nativeMethod; object targetMethod; + object originalMethod; CallTrace* next; }; @@ -1371,7 +1373,7 @@ releaseLock(MyThread* t, object method, void* stack) void findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) + void** targetStack, unsigned* oldArgumentFootprint = 0) { void* ip = t->ip; void* base = t->base; @@ -1386,7 +1388,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { - void* handler = findExceptionHandler(t, method, ip, forContinuation); + void* handler = findExceptionHandler(t, method, ip); if (handler) { *targetIp = handler; @@ -1418,12 +1420,16 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); + if (oldArgumentFootprint) { + *oldArgumentFootprint + = t->arch->argumentFootprint(methodParameterFootprint(t, target)); + } + while (t->continuation) { object method = continuationMethod(t, t->continuation); void* handler = findExceptionHandler - (t, method, continuationAddress(t, t->continuation), - forContinuation); + (t, method, continuationAddress(t, t->continuation)); if (handler) { t->exceptionHandler = handler; @@ -1548,6 +1554,9 @@ unwind(MyThread* t) object& objectPools(MyThread* t); +object& +rewindMethod(MyThread* t); + uintptr_t defaultThunk(MyThread* t); @@ -5309,15 +5318,33 @@ callContinuation(MyThread* t, object continuation, object result, vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } -uint8_t* +int8_t* returnSpec(MyThread* t, object method) { - uint8_t* s = &byteArrayBody(t, methodSpec(t, method)); + int8_t* s = &byteArrayBody(t, methodSpec(t, method), 0); while (*s and *s != ')') ++ s; expect(t, *s == ')'); return s + 1; } +object +returnClass(MyThread* t, object method) +{ + int8_t* spec = returnSpec(t, method); + unsigned length = strlen(reinterpret_cast(spec)); + object name; + if (*spec == '[') { + name = makeByteArray(t, length + 1); + memcpy(&byteArrayBody(t, name, 0), spec, length); + } else { + assert(t, *spec == 'L'); + assert(t, spec[length - 1] == ';'); + name = makeByteArray(t, length - 1); + memcpy(&byteArrayBody(t, name, 0), spec + 1, length - 2); + } + return resolveClass(t, name); +} + bool compatibleReturnType(MyThread* t, object oldMethod, object newMethod) { @@ -5326,10 +5353,14 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } else if (methodReturnCode(t, oldMethod) == methodReturnCode(t, newMethod)) { if (methodReturnCode(t, oldMethod) == ObjectField) { - uint8_t* oldSpec = returnSpec(t, oldMethod); - uint8_t* newSpec = returnSpec(t, newMethod); + PROTECT(t, newMethod); - + object oldClass = returnClass(t, oldMethod); + PROTECT(t, oldClass); + + object newClass = returnClass(t, newMethod); + + return isAssignableFrom(t, oldClass, newClass); } else { return true; } @@ -5338,120 +5369,6 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } } -object -findUnwindContinuation(MyThread* t, object oldContinuation, - object newContinuation) -{ - -} - -object -findRewindContinuation(MyThread* t, object oldContinuation, - object newContinuation) -{ - -} - -void -callContinuation(MyThread* t, object continuation, object result, - object exception) -{ - enum { - Call, - Unwind, - Rewind, - Throw - } action; - - object nextContinuation = 0; - - if (t->continuation == null - or continuationContext(t, t->continuation) - != continuationContext(t, continuation)) - { - PROTECT(t, continuation); - PROTECT(t, result); - PROTECT(t, exception); - - if (not compatibleReturnType - (t, t->trace->originalMethod, continuationContextMethod - (t, continuationContext(t, t->continuation)))) - { - t->exception = makeIncompatibleContinuationException(t); - action = Throw; - } else { - nextContinuation = findUnwindContinuation - (t, t->continuation, continuation); - - if (nextContinuation) { - result = makeUnwindResult(t, continuation, result, exception); - action = Unwind; - } else { - nextContinuation = findRewindContinuation - (t, t->continuation, continuation); - - if (nextContinuation) { - action = Rewind; - - if (rewindMethod(t) == 0) { - const char* const className = "avian/Continuations"; - const char* const methodName = "rewind"; - const char* const methodSpec - = "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" - "Ljava/lang/Throwable;)V"; - - object method = resolveMethod - (t, className, methodName, methodSpec); - - if (method) { - rewindMethod(t) == 0; - } else { - object message = makeString - (t, "%s %s not found in %s", - methodName, methodSpec, className); - - t->exception = makeNoSuchMethodError(t, message); - action = Throw; - } - } - } - } - } - } else { - action = Call; - } - - void* ip; - void* base; - void* stack; - findUnwindTarget(t, &ip, &base, &stack); - - switch (action) { - case Call: { - callContinuation - (t, unwindContinuation, result, exception, ip, base, stack); - } break; - - case Unwind: { - callContinuation(t, nextContinuation, result, 0, ip, base, stack); - } break; - - case Rewind: { - jumpAndInvoke - (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, - continuationContextBefore(t, nextContinuation), nextContinuation, - result, exception); - } break; - - case Throw: { - vmJump(ip, base, stack, t, 0, 0); - } break; - - default: - abort(t); - } -} - void jumpAndInvoke(MyThread* t, object method, void* base, void* stack, unsigned oldArgumentFootprint, unsigned argumentCount, @@ -5484,6 +5401,131 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, arguments); } +void +callContinuation(MyThread* t, object continuation, object result, + object exception) +{ + enum { + Call, + Unwind, + Rewind, + Throw + } action; + + object nextContinuation = 0; + + if (t->continuation == 0 + or continuationContext(t, t->continuation) + != continuationContext(t, continuation)) + { + PROTECT(t, continuation); + PROTECT(t, result); + PROTECT(t, exception); + + if (compatibleReturnType + (t, t->trace->originalMethod, continuationContextMethod + (t, continuationContext(t, t->continuation)))) + { + object oldContext; + object unwindContext; + + if (t->continuation) { + oldContext = continuationContext(t, t->continuation); + unwindContext = oldContext; + } else { + oldContext = 0; + unwindContext = 0; + } + + object rewindContext = 0; + + for (object newContext = continuationContext(t, continuation); + newContext; newContext = continuationContextNext(t, newContext)) + { + if (newContext == oldContext) { + unwindContext = 0; + break; + } else { + rewindContext = newContext; + } + } + + if (unwindContext + and continuationContextContinuation(t, unwindContext)) + { + nextContinuation = continuationContextContinuation(t, unwindContext); + result = makeUnwindResult(t, continuation, result, exception); + action = Unwind; + } else if (rewindContext + and continuationContextContinuation(t, rewindContext)) + { + nextContinuation = continuationContextContinuation(t, rewindContext); + action = Rewind; + + if (rewindMethod(t) == 0) { + PROTECT(t, nextContinuation); + + const char* const className = "avian/Continuations"; + const char* const methodName = "rewind"; + const char* const methodSpec + = "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" + "Ljava/lang/Throwable;)V"; + + object method = resolveMethod + (t, className, methodName, methodSpec); + + if (method) { + rewindMethod(t) = method; + } else { + object message = makeString + (t, "%s %s not found in %s", + methodName, methodSpec, className); + + t->exception = makeNoSuchMethodError(t, message); + action = Throw; + } + } + } + } else { + t->exception = makeIncompatibleContinuationException(t); + action = Throw; + } + } else { + action = Call; + } + + void* ip; + void* base; + void* stack; + unsigned oldArgumentFootprint; + findUnwindTarget(t, &ip, &base, &stack, &oldArgumentFootprint); + + switch (action) { + case Call: { + callContinuation + (t, nextContinuation, result, exception, ip, base, stack); + } break; + + case Unwind: { + callContinuation(t, nextContinuation, result, 0, ip, base, stack); + } break; + + case Rewind: { + jumpAndInvoke + (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, + continuationContextBefore(t, nextContinuation), nextContinuation, + result, exception); + } break; + + case Throw: { + vmJump(ip, base, stack, t, 0, 0); + } break; + + default: + abort(t); + } +} + class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, @@ -5618,11 +5660,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) uint64_t result; - { MyThread::CallTrace trace(t); - - if (methodFlags(t, method) & ACC_NATIVE) { - trace.nativeMethod = method; - } + { MyThread::CallTrace trace(t, method); assert(t, arguments->position == arguments->size); @@ -5745,6 +5783,8 @@ class MyProcessor: public Processor { staticTableArray(0), virtualThunks(0), receiveMethod(0), + windMethod(0), + rewindMethod(0), codeAllocator(s, 0, 0) { } @@ -5839,12 +5879,15 @@ class MyProcessor: public Processor { v->visit(&staticTableArray); v->visit(&virtualThunks); v->visit(&receiveMethod); + v->visit(&windMethod); + v->visit(&rewindMethod); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { v->visit(&(trace->continuation)); v->visit(&(trace->nativeMethod)); v->visit(&(trace->targetMethod)); + v->visit(&(trace->originalMethod)); } v->visit(&(t->continuation)); @@ -6255,7 +6298,7 @@ class MyProcessor: public Processor { if (LIKELY(t->exception == 0)) { jumpAndInvoke - (t, method, base, stack, oldArgumentFootprint, 3, before, thunk, + (t, windMethod, base, stack, oldArgumentFootprint, 3, before, thunk, after); } else { unwind(t); @@ -6296,6 +6339,8 @@ class MyProcessor: public Processor { object staticTableArray; object virtualThunks; object receiveMethod; + object windMethod; + object rewindMethod; SegFaultHandler segFaultHandler; FixedAllocator codeAllocator; }; @@ -6906,6 +6951,12 @@ objectPools(MyThread* t) return processor(t)->objectPools; } +object& +rewindMethod(MyThread* t) +{ + return processor(t)->rewindMethod; +} + uintptr_t defaultThunk(MyThread* t) { diff --git a/src/machine.h b/src/machine.h index 024ac84f12..67e2dbf071 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1726,6 +1726,12 @@ makeInterruptedException(Thread* t) return makeInterruptedException(t, 0, makeTrace(t), 0); } +inline object +makeIncompatibleContinuationException(Thread* t) +{ + return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0); +} + inline object makeStackOverflowError(Thread* t) { diff --git a/src/processor.h b/src/processor.h index 7777953580..13d4328d5f 100644 --- a/src/processor.h +++ b/src/processor.h @@ -136,6 +136,9 @@ class Processor { virtual void callWithCurrentContinuation(Thread* t, object receiver) = 0; + virtual void + dynamicWind(Thread* t, object before, object thunk, object after) = 0; + virtual void feedResultToContinuation(Thread* t, object continuation, object result) = 0; diff --git a/src/types.def b/src/types.def index 34fd77a985..c3d711c18a 100644 --- a/src/types.def +++ b/src/types.def @@ -175,6 +175,9 @@ (type exceptionInInitializerError java/lang/ExceptionInInitializerError) +(type incompatibleContinuationException + avian/IncompatibleContinuationException) + (type number java/lang/Number) (type byte java/lang/Byte)