finish initial sketch of dynamicWind implementation

This commit is contained in:
Joel Dice 2009-05-23 19:49:14 -06:00
parent 4305fdc7f3
commit 364f31b785
5 changed files with 200 additions and 137 deletions

View File

@ -21,27 +21,27 @@ public abstract class Continuations {
Runnable after) Runnable after)
throws Exception throws Exception
{ {
UnwindResult result = dynamicWind2(buffer, thunk, after); UnwindResult result = dynamicWind2(before, thunk, after);
if (result.continuation != null) { if (result.continuation != null) {
after.run(); after.run();
if (result.exception != null) { if (result.exception != null) {
result.continuation.handleException(result.exception); result.continuation.handleException(result.exception);
} else { } else {
result.continuation.handleResult(result.value); result.continuation.handleResult(result.result);
} }
throw new AssertionError(); throw new AssertionError();
} else { } else {
return (T) result.value; return (T) result.result;
} }
} }
private static native UnwindResult dynamicWind2(Runnable before, private static native UnwindResult dynamicWind2(Runnable before,
Callable<T> thunk, Callable thunk,
Runnable after) Runnable after)
throws Exception; throws Exception;
private static UnwindResult wind(Runnable before, private static UnwindResult wind(Runnable before,
Callable<T> thunk, Callable thunk,
Runnable after) Runnable after)
throws Exception throws Exception
{ {
@ -65,7 +65,7 @@ public abstract class Continuations {
if (exception != null) { if (exception != null) {
continuation.handleException(exception); continuation.handleException(exception);
} else { } else {
continuation.handleResult(value); continuation.handleResult(result);
} }
throw new AssertionError(); throw new AssertionError();

View File

@ -49,13 +49,14 @@ class MyThread: public Thread {
public: public:
class CallTrace { class CallTrace {
public: public:
CallTrace(MyThread* t): CallTrace(MyThread* t, object method):
t(t), t(t),
base(t->base), base(t->base),
stack(t->stack), stack(t->stack),
continuation(t->continuation), continuation(t->continuation),
nativeMethod(0), nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0),
targetMethod(0), targetMethod(0),
originalMethod(method),
next(t->trace) next(t->trace)
{ {
t->trace = this; t->trace = this;
@ -77,6 +78,7 @@ class MyThread: public Thread {
object continuation; object continuation;
object nativeMethod; object nativeMethod;
object targetMethod; object targetMethod;
object originalMethod;
CallTrace* next; CallTrace* next;
}; };
@ -1371,7 +1373,7 @@ releaseLock(MyThread* t, object method, void* stack)
void void
findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
void** targetStack) void** targetStack, unsigned* oldArgumentFootprint = 0)
{ {
void* ip = t->ip; void* ip = t->ip;
void* base = t->base; void* base = t->base;
@ -1386,7 +1388,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
while (*targetIp == 0) { while (*targetIp == 0) {
object method = methodForIp(t, ip); object method = methodForIp(t, ip);
if (method) { if (method) {
void* handler = findExceptionHandler(t, method, ip, forContinuation); void* handler = findExceptionHandler(t, method, ip);
if (handler) { if (handler) {
*targetIp = handler; *targetIp = handler;
@ -1418,12 +1420,16 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
*targetStack = static_cast<void**>(stack) *targetStack = static_cast<void**>(stack)
+ t->arch->frameReturnAddressSize(); + t->arch->frameReturnAddressSize();
if (oldArgumentFootprint) {
*oldArgumentFootprint
= t->arch->argumentFootprint(methodParameterFootprint(t, target));
}
while (t->continuation) { while (t->continuation) {
object method = continuationMethod(t, t->continuation); object method = continuationMethod(t, t->continuation);
void* handler = findExceptionHandler void* handler = findExceptionHandler
(t, method, continuationAddress(t, t->continuation), (t, method, continuationAddress(t, t->continuation));
forContinuation);
if (handler) { if (handler) {
t->exceptionHandler = handler; t->exceptionHandler = handler;
@ -1548,6 +1554,9 @@ unwind(MyThread* t)
object& object&
objectPools(MyThread* t); objectPools(MyThread* t);
object&
rewindMethod(MyThread* t);
uintptr_t uintptr_t
defaultThunk(MyThread* t); defaultThunk(MyThread* t);
@ -5309,15 +5318,33 @@ callContinuation(MyThread* t, object continuation, object result,
vmJump(ip, base, stack, t, reinterpret_cast<uintptr_t>(result), 0); vmJump(ip, base, stack, t, reinterpret_cast<uintptr_t>(result), 0);
} }
uint8_t* int8_t*
returnSpec(MyThread* t, object method) 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; while (*s and *s != ')') ++ s;
expect(t, *s == ')'); expect(t, *s == ')');
return s + 1; return s + 1;
} }
object
returnClass(MyThread* t, object method)
{
int8_t* spec = returnSpec(t, method);
unsigned length = strlen(reinterpret_cast<char*>(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 bool
compatibleReturnType(MyThread* t, object oldMethod, object newMethod) 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)) } else if (methodReturnCode(t, oldMethod) == methodReturnCode(t, newMethod))
{ {
if (methodReturnCode(t, oldMethod) == ObjectField) { if (methodReturnCode(t, oldMethod) == ObjectField) {
uint8_t* oldSpec = returnSpec(t, oldMethod); PROTECT(t, newMethod);
uint8_t* newSpec = returnSpec(t, newMethod);
object oldClass = returnClass(t, oldMethod);
PROTECT(t, oldClass);
object newClass = returnClass(t, newMethod);
return isAssignableFrom(t, oldClass, newClass);
} else { } else {
return true; 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 void
jumpAndInvoke(MyThread* t, object method, void* base, void* stack, jumpAndInvoke(MyThread* t, object method, void* base, void* stack,
unsigned oldArgumentFootprint, unsigned argumentCount, unsigned oldArgumentFootprint, unsigned argumentCount,
@ -5484,6 +5401,131 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack,
arguments); 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 { class ArgumentList {
public: public:
ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask,
@ -5618,11 +5660,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
uint64_t result; uint64_t result;
{ MyThread::CallTrace trace(t); { MyThread::CallTrace trace(t, method);
if (methodFlags(t, method) & ACC_NATIVE) {
trace.nativeMethod = method;
}
assert(t, arguments->position == arguments->size); assert(t, arguments->position == arguments->size);
@ -5745,6 +5783,8 @@ class MyProcessor: public Processor {
staticTableArray(0), staticTableArray(0),
virtualThunks(0), virtualThunks(0),
receiveMethod(0), receiveMethod(0),
windMethod(0),
rewindMethod(0),
codeAllocator(s, 0, 0) codeAllocator(s, 0, 0)
{ } { }
@ -5839,12 +5879,15 @@ class MyProcessor: public Processor {
v->visit(&staticTableArray); v->visit(&staticTableArray);
v->visit(&virtualThunks); v->visit(&virtualThunks);
v->visit(&receiveMethod); v->visit(&receiveMethod);
v->visit(&windMethod);
v->visit(&rewindMethod);
} }
for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) {
v->visit(&(trace->continuation)); v->visit(&(trace->continuation));
v->visit(&(trace->nativeMethod)); v->visit(&(trace->nativeMethod));
v->visit(&(trace->targetMethod)); v->visit(&(trace->targetMethod));
v->visit(&(trace->originalMethod));
} }
v->visit(&(t->continuation)); v->visit(&(t->continuation));
@ -6255,7 +6298,7 @@ class MyProcessor: public Processor {
if (LIKELY(t->exception == 0)) { if (LIKELY(t->exception == 0)) {
jumpAndInvoke jumpAndInvoke
(t, method, base, stack, oldArgumentFootprint, 3, before, thunk, (t, windMethod, base, stack, oldArgumentFootprint, 3, before, thunk,
after); after);
} else { } else {
unwind(t); unwind(t);
@ -6296,6 +6339,8 @@ class MyProcessor: public Processor {
object staticTableArray; object staticTableArray;
object virtualThunks; object virtualThunks;
object receiveMethod; object receiveMethod;
object windMethod;
object rewindMethod;
SegFaultHandler segFaultHandler; SegFaultHandler segFaultHandler;
FixedAllocator codeAllocator; FixedAllocator codeAllocator;
}; };
@ -6906,6 +6951,12 @@ objectPools(MyThread* t)
return processor(t)->objectPools; return processor(t)->objectPools;
} }
object&
rewindMethod(MyThread* t)
{
return processor(t)->rewindMethod;
}
uintptr_t uintptr_t
defaultThunk(MyThread* t) defaultThunk(MyThread* t)
{ {

View File

@ -1726,6 +1726,12 @@ makeInterruptedException(Thread* t)
return makeInterruptedException(t, 0, makeTrace(t), 0); return makeInterruptedException(t, 0, makeTrace(t), 0);
} }
inline object
makeIncompatibleContinuationException(Thread* t)
{
return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0);
}
inline object inline object
makeStackOverflowError(Thread* t) makeStackOverflowError(Thread* t)
{ {

View File

@ -136,6 +136,9 @@ class Processor {
virtual void virtual void
callWithCurrentContinuation(Thread* t, object receiver) = 0; callWithCurrentContinuation(Thread* t, object receiver) = 0;
virtual void
dynamicWind(Thread* t, object before, object thunk, object after) = 0;
virtual void virtual void
feedResultToContinuation(Thread* t, object continuation, object result) = 0; feedResultToContinuation(Thread* t, object continuation, object result) = 0;

View File

@ -175,6 +175,9 @@
(type exceptionInInitializerError java/lang/ExceptionInInitializerError) (type exceptionInInitializerError java/lang/ExceptionInInitializerError)
(type incompatibleContinuationException
avian/IncompatibleContinuationException)
(type number java/lang/Number) (type number java/lang/Number)
(type byte java/lang/Byte) (type byte java/lang/Byte)