begin dynamicWind implementation

This commit is contained in:
Joel Dice 2009-05-23 16:15:06 -06:00
parent e165d5f3fd
commit 4305fdc7f3
5 changed files with 398 additions and 85 deletions

View File

@ -16,12 +16,77 @@ public abstract class Continuations {
public static native <T> T callWithCurrentContinuation
(CallbackReceiver<T> receiver) throws Exception;
public static native <T> T dynamicWind(Runnable before,
Callable<T> thunk,
Runnable after) throws Exception;
public static <T> T dynamicWind(Runnable before,
Callable<T> thunk,
Runnable after)
throws Exception
{
UnwindResult result = dynamicWind2(buffer, thunk, after);
if (result.continuation != null) {
after.run();
if (result.exception != null) {
result.continuation.handleException(result.exception);
} else {
result.continuation.handleResult(result.value);
}
throw new AssertionError();
} else {
return (T) result.value;
}
}
private static native UnwindResult dynamicWind2(Runnable before,
Callable<T> thunk,
Runnable after)
throws Exception;
private static UnwindResult wind(Runnable before,
Callable<T> thunk,
Runnable after)
throws Exception
{
before.run();
try {
return new UnwindResult(null, thunk.call(), null);
} finally {
after.run();
}
}
private static void rewind(Runnable before,
Callback continuation,
Object result,
Throwable exception)
throws Exception
{
before.run();
if (exception != null) {
continuation.handleException(exception);
} else {
continuation.handleResult(value);
}
throw new AssertionError();
}
private static class Continuation<T> implements Callback<T> {
public native void handleResult(T result);
public native void handleException(Throwable exception);
}
private static class UnwindResult {
public final Callback continuation;
public final Object result;
public final Throwable exception;
public UnwindResult(Callback continuation, Object result,
Throwable exception)
{
this.continuation = continuation;
this.result = result;
this.exception = exception;
}
}
}

View File

@ -849,9 +849,8 @@ Java_java_net_URL_00024ResourceInputStream_close(Thread*, jclass, jlong peer)
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Continuations_callWithCurrentContinuation(Thread* t,
object,
uintptr_t* arguments)
Avian_avian_Continuations_callWithCurrentContinuation
(Thread* t, object, uintptr_t* arguments)
{
t->m->processor->callWithCurrentContinuation
(t, reinterpret_cast<object>(*arguments));
@ -859,6 +858,18 @@ Avian_avian_Continuations_callWithCurrentContinuation(Thread* t,
abort(t);
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Continuations_dynamicWind2
(Thread* t, object, uintptr_t* arguments)
{
t->m->processor->dynamicWind
(t, reinterpret_cast<object>(arguments[0]),
reinterpret_cast<object>(arguments[1]),
reinterpret_cast<object>(arguments[2]));
abort(t);
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Continuations_00024Continuation_handleResult
(Thread* t, object, uintptr_t* arguments)

View File

@ -23,11 +23,11 @@
#define THREAD_EXCEPTION_HANDLER 192
#define CONTINUATION_NEXT 8
#define CONTINUATION_ADDRESS 24
#define CONTINUATION_RETURN_ADDRESS_OFFSET 32
#define CONTINUATION_FRAME_POINTER_OFFSET 40
#define CONTINUATION_LENGTH 48
#define CONTINUATION_BODY 56
#define CONTINUATION_ADDRESS 32
#define CONTINUATION_RETURN_ADDRESS_OFFSET 40
#define CONTINUATION_FRAME_POINTER_OFFSET 48
#define CONTINUATION_LENGTH 56
#define CONTINUATION_BODY 64
.globl vmInvoke
vmInvoke:
@ -145,22 +145,36 @@ LOCAL(vmInvoke_exit):
popq %rbp
ret
.globl vmCallWithContinuation
vmCallWithContinuation:
.globl vmJumpAndInvoke
vmJumpAndInvoke:
// %rdi: thread
// %rsi: address
// %rdx: targetObject
// %rcx: continuation
// %r8 : base
// %r9 : stack
// %rdx: base
// %rcx: stack
// %r8 : argumentFootprint
// %r9 : arguments
movq %rdi,%rbx
movq %r8,%rbp
movq %r9,%rsp
// set return address
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
movq %r10,(%rsp)
movq %rdx,8(%rsp)
movq %rcx,16(%rsp)
// copy arguments into place
movq $0,%r11
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movq (%r8,%r11,1),%r10
movq %r10,8(%rsp,%r11,1)
addq $8,%r11
LOCAL(vmJumpAndInvoke_argumentTest):
cmpq %r8,%r11
jb LOCAL(vmJumpAndInvoke_argumentLoop)
movq %rdi,%rbx
movq %rdx,%rbp
movq %rcx,%rsp
jmp *%rsi
#elif defined __i386__

View File

@ -22,9 +22,9 @@ extern "C" uint64_t
vmInvoke(void* thread, void* function, void* arguments,
unsigned argumentFootprint, unsigned frameSize, unsigned returnType);
extern "C" uint64_t
vmCallWithContinuation(void* thread, void* function, void* targetObject,
object continuation, void* base, void* stack);
extern "C" void
vmJumpAndInvoke(void* thread, void* function, void* base, void* stack,
unsigned argumentFootprint, uintptr_t* arguments);
extern "C" void
vmCall();
@ -1386,7 +1386,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
while (*targetIp == 0) {
object method = methodForIp(t, ip);
if (method) {
void* handler = findExceptionHandler(t, method, ip);
void* handler = findExceptionHandler(t, method, ip, forContinuation);
if (handler) {
*targetIp = handler;
@ -1406,7 +1406,9 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
t->arch->nextFrame(&stack, &base);
ip = t->arch->frameIp(stack);
releaseLock(t, method, stack);
if (t->exception) {
releaseLock(t, method, stack);
}
target = method;
}
@ -1420,7 +1422,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
object method = continuationMethod(t, t->continuation);
void* handler = findExceptionHandler
(t, method, continuationAddress(t, t->continuation));
(t, method, continuationAddress(t, t->continuation),
forContinuation);
if (handler) {
t->exceptionHandler = handler;
@ -1433,7 +1436,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
t->exceptionOffset
= localOffset(t, localSize(t, method), method) * BytesPerWord;
break;
} else {
} else if (t->exception) {
releaseLock(t, method,
reinterpret_cast<uint8_t*>(t->continuation)
+ ContinuationBody
@ -1448,9 +1451,12 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
}
object
makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase,
void** targetStack, unsigned* oldArgumentFootprint)
makeCurrentContinuation(MyThread* t, object context, void** targetIp,
void** targetBase, void** targetStack,
unsigned* oldArgumentFootprint)
{
PROTECT(t, context);
void* ip = t->ip;
void* base = t->base;
void* stack = t->stack;
@ -1492,7 +1498,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase,
+ t->arch->argumentFootprint(methodParameterFootprint(t, method));
object c = makeContinuation
(t, 0, method, ip,
(t, 0, context, method, ip,
((frameSize
+ t->arch->returnAddressOffset()
- t->arch->frameReturnAddressSize()) * BytesPerWord),
@ -5280,9 +5286,176 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start)
}
void
callWithContinuation(MyThread* t, object method, object this_,
object continuation, void* base, void* stack,
unsigned oldArgumentFootprint)
callContinuation(MyThread* t, object continuation, object result,
object exception, void* ip, void* base, void* stack)
{
assert(t, t->exception == 0);
t->trace->nativeMethod = 0;
t->trace->targetMethod = 0;
t->continuation = continuation;
if (exception) {
t->exception = exception;
t->ip = ip;
t->base = base;
t->stack = stack;
findUnwindTarget(t, &ip, &base, &stack);
}
vmJump(ip, base, stack, t, reinterpret_cast<uintptr_t>(result), 0);
}
uint8_t*
returnSpec(MyThread* t, object method)
{
uint8_t* s = &byteArrayBody(t, methodSpec(t, method));
while (*s and *s != ')') ++ s;
expect(t, *s == ')');
return s + 1;
}
bool
compatibleReturnType(MyThread* t, object oldMethod, object newMethod)
{
if (oldMethod == newMethod) {
return true;
} 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);
} else {
return true;
}
} else {
return methodReturnCode(t, oldMethod) == VoidField;
}
}
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,
...)
{
t->trace->targetMethod = 0;
@ -5291,17 +5464,24 @@ callWithContinuation(MyThread* t, object method, object this_,
} else {
t->trace->nativeMethod = 0;
}
uintptr_t arguments[argumentCount];
va_list a; va_start(a, argumentCount);
for (unsigned i = 0; i < argumentCount; ++i) {
arguments[i] = va_arg(a, uintptr_t);
}
va_end(a);
vmCallWithContinuation
vmJumpAndInvoke
(t, reinterpret_cast<void*>(methodAddress(t, method)),
this_,
continuation,
base,
static_cast<void**>(stack)
+ oldArgumentFootprint
- t->arch->argumentFootprint(methodParameterFootprint(t, method))
- t->arch->frameFooterSize()
- t->arch->frameReturnAddressSize());
- t->arch->frameReturnAddressSize(),
argumentCount * BytesPerWord,
arguments);
}
class ArgumentList {
@ -5968,6 +6148,12 @@ class MyProcessor: public Processor {
virtual void callWithCurrentContinuation(Thread* vmt, object receiver) {
MyThread* t = static_cast<MyThread*>(vmt);
object method = 0;
void* ip = 0;
void* base = 0;
void* stack = 0;
unsigned oldArgumentFootprint = 0;
{ PROTECT(t, receiver);
if (receiveMethod == 0) {
@ -5994,71 +6180,98 @@ class MyProcessor: public Processor {
}
if (LIKELY(t->exception == 0)) {
object method = findInterfaceMethod
method = findInterfaceMethod
(t, receiveMethod, objectClass(t, receiver));
PROTECT(t, method);
compile(t, ::codeAllocator(t), 0, method);
if (LIKELY(t->exception == 0)) {
void* ip;
void* base;
void* stack;
unsigned oldArgumentFootprint;
t->continuation = makeCurrentContinuation
(t, &ip, &base, &stack, &oldArgumentFootprint);
callWithContinuation
(t, method, receiver, t->continuation, base, stack,
oldArgumentFootprint);
if (LIKELY(t->exception == 0)) {
t->continuation = makeCurrentContinuation
(t, t->continuation
? continuationContext(t, t->continuation)
: makeContinuationContext
(t, 0, 0, 0, 0, t->trace->originalMethod),
&ip, &base, &stack, &oldArgumentFootprint);
}
}
}
unwind(t);
if (LIKELY(t->exception == 0)) {
jumpAndInvoke
(t, method, base, stack, oldArgumentFootprint, 2, receiver,
t->continuation);
} else {
unwind(t);
}
}
virtual void dynamicWind(Thread* vmt, object before, object thunk,
object after)
{
MyThread* t = static_cast<MyThread*>(vmt);
void* ip = 0;
void* base = 0;
void* stack = 0;
unsigned oldArgumentFootprint = 0;
{ PROTECT(t, before);
PROTECT(t, thunk);
PROTECT(t, after);
if (windMethod == 0) {
const char* const className = "avian/Continuations";
const char* const methodName = "wind";
const char* const methodSpec
= "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;"
"Ljava/lang/Runnable;)Ljava/lang/Object;";
windMethod = resolveMethod(t, className, methodName, methodSpec);
if (windMethod == 0) {
object message = makeString
(t, "%s %s not found in %s", methodName, methodSpec, className);
t->exception = makeNoSuchMethodError(t, message);
}
}
if (LIKELY(t->exception == 0)) {
object oldContext
= (t->continuation ? continuationContext(t, t->continuation) : 0);
object context = makeContinuationContext
(t, oldContext, before, after, 0, t->trace->originalMethod);
object continuation = makeCurrentContinuation
(t, context, &ip, &base, &stack, &oldArgumentFootprint);
set(t, continuationContext(t, continuation),
ContinuationContextContinuation, continuation);
t->continuation = continuation;
}
}
if (LIKELY(t->exception == 0)) {
jumpAndInvoke
(t, method, base, stack, oldArgumentFootprint, 3, before, thunk,
after);
} else {
unwind(t);
}
}
virtual void feedResultToContinuation(Thread* vmt, object continuation,
object result)
{
MyThread* t = static_cast<MyThread*>(vmt);
assert(t, t->exception == 0);
void* ip;
void* base;
void* stack;
findUnwindTarget(t, &ip, &base, &stack);
t->trace->nativeMethod = 0;
t->trace->targetMethod = 0;
t->continuation = continuation;
vmJump(ip, base, stack, t, reinterpret_cast<uintptr_t>(result), 0);
callContinuation(static_cast<MyThread*>(vmt), continuation, result, 0);
}
virtual void feedExceptionToContinuation(Thread* vmt, object continuation,
object exception)
{
MyThread* t = static_cast<MyThread*>(vmt);
assert(t, t->exception == 0);
void* ip;
void* base;
void* stack;
findUnwindTarget(t, &ip, &base, &stack);
t->trace->nativeMethod = 0;
t->trace->targetMethod = 0;
t->continuation = continuation;
t->exception = exception;
findUnwindTarget(t, &ip, &base, &stack);
vmJump(ip, base, stack, t, 0, 0);
callContinuation(static_cast<MyThread*>(vmt), continuation, 0, exception);
}
virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o,

View File

@ -104,14 +104,24 @@
(type array
(noassert array object body))
(type continuationContext
(object next)
(object before)
(object after)
(object continuation)
(object method))
(type continuation avian/Continuations$Continuation
(object next)
(object context)
(object method)
(void* address)
(uintptr_t returnAddressOffset)
(uintptr_t framePointerOffset)
(array uintptr_t body))
(type unwindResult avian/Continuations$UnwindResult)
(type callbackReceiver avian/CallbackReceiver)
(type string java/lang/String)