Squashed commit of the following: (#32)

commit a25c09bb738e7e82d2dfd909381ba052f7b69687
Merge: aa6664214 92af5d169
Author: Joel Dice <joel.dice@gmail.com>
Date:   Tue Sep 5 11:38:08 2017 -0600

    Merge pull request #545 from corda/chrisr3-uncaught-exceptions

    Support Thread.uncaughtExceptionHandler with OpenJDK

commit aa666421499d0e9ed46b6c745a93abd9998a58b0
Merge: dc8c99bd2 1cb11e964
Author: Joel Dice <joel.dice@gmail.com>
Date:   Tue Sep 5 11:23:41 2017 -0600

    Merge pull request #546 from corda/chrisr3-werror

    Fix "fallthrough" warnings with recent GCC.

commit dc8c99bd2f045c787f2c322cd65f866626fa9461
Author: Joel Dice <joel.dice@gmail.com>
Date:   Tue Sep 5 11:17:54 2017 -0600

    fix bootimage-test build regression

commit 1cb11e964fab925e9d98373ba58e181b1a1f11fd
Author: Chris Rankin <chris.rankin@r3.com>
Date:   Tue Sep 5 10:25:48 2017 +0100

    Fix "fallthrough" warnings with recent GCC.

commit 92af5d169dbfb7b9b9f5b667b0dc71ca7b98b416
Author: Chris Rankin <chris.rankin@r3.com>
Date:   Mon Sep 4 17:26:31 2017 +0100

    Ensure that the thread resources are only cleaned up once.

commit 05d260f8bed68e3f999619aee338a781ba0f4c63
Author: Chris Rankin <chris.rankin@r3.com>
Date:   Mon Sep 4 17:10:04 2017 +0100

    Test exception thrown from uncaught-exception handler.

commit b1c5dca36163a876fba86221493883ddbd5fe805
Author: Chris Rankin <chris.rankin@r3.com>
Date:   Tue Aug 29 17:17:24 2017 +0100

    Support Thread.uncaughtExceptionHandler.
This commit is contained in:
Chris Rankin 2017-09-06 10:48:26 +01:00 committed by GitHub
parent e075e52377
commit c0c75c3e19
6 changed files with 132 additions and 27 deletions

View File

@ -296,6 +296,10 @@ object makeJconstructor(Thread* t, GcMethod* vmMethod, int index = -1);
object makeJfield(Thread* t, GcField* vmField, int index = -1); object makeJfield(Thread* t, GcField* vmField, int index = -1);
void uncaughtException(Thread *t, GcThrowable *e);
void disposeThread(Thread *t);
#ifdef AVIAN_OPENJDK_SRC #ifdef AVIAN_OPENJDK_SRC
void interceptFileOperations(Thread*, bool); void interceptFileOperations(Thread*, bool);
#endif #endif
@ -588,22 +592,15 @@ class MyClasspath : public Classpath {
objectMonitor(t, t->javaThread, true); objectMonitor(t, t->javaThread, true);
THREAD_RESOURCE0(t, { THREAD_RESOURCE0(t, {
vm::acquire(t, t->javaThread);
t->clearFlag(Thread::ActiveFlag);
vm::notifyAll(t, t->javaThread);
vm::release(t, t->javaThread);
GcThrowable* e = t->exception; GcThrowable* e = t->exception;
if (e != NULL) {
PROTECT(t, e); PROTECT(t, e);
t->exception = 0; t->exception = NULL;
uncaughtException(t, e);
}
t->m->processor->invoke(t, disposeThread(t);
cast<GcMethod>(t, roots(t)->threadTerminated()),
t->javaThread->group(),
t->javaThread);
t->exception = e;
}); });
GcMethod* method = resolveMethod( GcMethod* method = resolveMethod(
@ -972,6 +969,43 @@ class EmbeddedFile {
unsigned pathLength; unsigned pathLength;
}; };
void uncaughtException(Thread *t, GcThrowable *e)
{
GcMethod* dispatch = resolveMethod(t,
roots(t)->bootLoader(),
"java/lang/Thread",
"dispatchUncaughtException",
"(Ljava/lang/Throwable;)V");
if (dispatch != NULL) {
THREAD_RESOURCE0(t, {
if (t->exception != NULL) {
// We ignore any exceptions from the uncaught
// exception handler itself.
t->exception = NULL;
// The stack will be unwound when this resource is
// released, which means that uncaughtException()
// will not return. So repeat the thread clean-up here.
disposeThread(t);
}
});
t->m->processor->invoke(t, dispatch, t->javaThread, e);
}
}
void disposeThread(Thread *t) {
vm::acquire(t, t->javaThread);
t->clearFlag(Thread::ActiveFlag);
vm::notifyAll(t, t->javaThread);
vm::release(t, t->javaThread);
t->m->processor->invoke(t,
cast<GcMethod>(t, roots(t)->threadTerminated()),
t->javaThread->group(),
t->javaThread);
}
#ifdef AVIAN_OPENJDK_SRC #ifdef AVIAN_OPENJDK_SRC
int64_t JNICALL int64_t JNICALL
getFileAttributes(Thread* t, GcMethod* method, uintptr_t* arguments) getFileAttributes(Thread* t, GcMethod* method, uintptr_t* arguments)

View File

@ -4029,13 +4029,13 @@ bool isLambda(Thread* t,
GcCharArray* bootstrapArray, GcCharArray* bootstrapArray,
GcInvocation* invocation) GcInvocation* invocation)
{ {
GcMethod* bootstrap = cast<GcMethod>(t, GcMethod* bootstrap = cast<GcMethodHandle>(t,
resolve(t, resolve(t,
loader, loader,
invocation->pool(), invocation->pool(),
bootstrapArray->body()[0], bootstrapArray->body()[0],
findMethodInClass, findMethodInClass,
GcNoSuchMethodError::Type)); GcNoSuchMethodError::Type))->method();
PROTECT(t, bootstrap); PROTECT(t, bootstrap);
return vm::strcmp(reinterpret_cast<const int8_t*>( return vm::strcmp(reinterpret_cast<const int8_t*>(
@ -5191,14 +5191,8 @@ loop:
"I" "I"
")[B"); ")[B");
GcReference* reference = cast<GcReference>( GcMethodHandle* handle
t, = cast<GcMethodHandle>(t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
GcMethod* method
= cast<GcMethod>(t,
resolve(t, resolve(t,
c->loader(), c->loader(),
invocation->pool(), invocation->pool(),
@ -5206,6 +5200,10 @@ loop:
findMethodInClass, findMethodInClass,
GcNoSuchMethodError::Type)); GcNoSuchMethodError::Type));
int kind = handle->kind();
GcMethod* method = handle->method();
jarray lambda = e->vtable->CallStaticObjectMethod( jarray lambda = e->vtable->CallStaticObjectMethod(
e, e,
lmfClass, lmfClass,

View File

@ -571,6 +571,7 @@ int printInstruction(uint8_t* code, unsigned& ip, const char* prefix)
return fprintf(stderr, "wide astore %4d", read16(code, ip)); return fprintf(stderr, "wide astore %4d", read16(code, ip));
case iinc: case iinc:
fprintf(stderr, "wide iinc %4d %4d", read16(code, ip), read16(code, ip)); fprintf(stderr, "wide iinc %4d %4d", read16(code, ip), read16(code, ip));
/* fallthrough */
case iload: case iload:
return fprintf(stderr, "wide iload %4d", read16(code, ip)); return fprintf(stderr, "wide iload %4d", read16(code, ip));
case istore: case istore:
@ -582,10 +583,10 @@ int printInstruction(uint8_t* code, unsigned& ip, const char* prefix)
case ret: case ret:
return fprintf(stderr, "wide ret %4d", read16(code, ip)); return fprintf(stderr, "wide ret %4d", read16(code, ip));
default: { default:
fprintf( fprintf(
stderr, "unknown wide instruction %2d %4d", instr, read16(code, ip)); stderr, "unknown wide instruction %2d %4d", instr, read16(code, ip));
} break;
} }
} }

View File

@ -4105,6 +4105,7 @@ void enter(Thread* t, Thread::State s)
} else { } else {
// fall through to slow path // fall through to slow path
} }
/* fallthrough */
case Thread::ZombieState: { case Thread::ZombieState: {
ACQUIRE_LOCK; ACQUIRE_LOCK;
@ -6189,7 +6190,7 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
} }
// `i` iterates through the bootstrap arguments (the +1 is because we skip // `i` iterates through the bootstrap arguments (the +1 is because we skip
// the boostrap method's name), `it` iterates through the corresponding types // the bootstrap method's name), `it` iterates through the corresponding types
// in the method signature // in the method signature
unsigned i = 0; unsigned i = 0;
while (i + 1 < bootstrapArray->length() && it.hasNext()) { while (i + 1 < bootstrapArray->length() && it.hasNext()) {

View File

@ -0,0 +1,71 @@
public class ThreadExceptions {
private static void expect(boolean v) {
if (! v) throw new RuntimeException("Expectation failed");
}
private static class Handler implements Thread.UncaughtExceptionHandler {
public String message;
@Override
public void uncaughtException(Thread t, Throwable e) {
message = e.getMessage();
}
}
public static void main(String[] args) throws Exception {
{ Thread thread = new Thread() {
@Override
public void run() {
throw new RuntimeException("TEST-DEFAULT-HANDLER");
}
};
Handler handler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(handler);
thread.start();
thread.join();
expect("TEST-DEFAULT-HANDLER".equals(handler.message));
}
Thread.setDefaultUncaughtExceptionHandler(null);
{ Thread thread = new Thread() {
@Override
public void run() {
throw new RuntimeException("TEST-HANDLER");
}
};
Handler handler = new Handler();
thread.setUncaughtExceptionHandler(handler);
thread.start();
thread.join();
expect("TEST-HANDLER".equals(handler.message));
}
{ Thread thread = new Thread() {
@Override
public void run() {
throw new RuntimeException("TEST-BAD-HANDLER");
}
};
Handler handler = new Handler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
super.uncaughtException(t, e);
throw new IllegalStateException("BAD THING");
}
};
thread.setUncaughtExceptionHandler(handler);
thread.start();
thread.join();
expect("TEST-BAD-HANDLER".equals(handler.message));
System.out.println("Exception from UncaughtExceptionHandler was ignored");
}
}
}

View File

@ -6,7 +6,7 @@ public class Threads implements Runnable {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
((Thread.UncaughtExceptionHandler) Thread.currentThread().getThreadGroup()) Thread.currentThread().getThreadGroup()
.uncaughtException(Thread.currentThread(), new Exception()); .uncaughtException(Thread.currentThread(), new Exception());
{ Threads test = new Threads(); { Threads test = new Threads();