ReadyTalk / avian

[INACTIVE] Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications.
https://readytalk.github.io/avian/
Other
1.22k stars 172 forks source link

Support Thread.uncaughtExceptionHandler with OpenJDK #545

Closed chrisr3 closed 7 years ago

chrisr3 commented 7 years ago

I have noticed that Avian doesn't support Thread.uncaughtExceptionHandler properly when compiled with OpenJDK. This PR almost does what I need except that I have noticed that the test cases are failing because Thread.join() isn't waiting for the uncaughtExceptionHandler to be executed.

The test case passes when Avian is not compiled against OpenJDK, e.g.

$ make clean test

My test case also passes when executed by both Oracle's JVM and OpenJDK itself, and all JVMs (including Avian) execute uncaughtExceptionHandler in the child thread. It therefore seems reasonable for Thread.join() to wait until the handler has executed too.

I have refactored how this works so that uncaughtExceptionHandler is now invoked before ActiveFlag is cleared. This allows Thread.join() to wait correctly.

chrisr3 commented 7 years ago

Not sure what this Travis build error is about, because the failing configuration doesn't have anything to do with classpath-openjdk.cpp.

This command no longer works for me on the master branch:

make bootimage=true bootimage-test=true test

See #547

dicej commented 7 years ago

I'm going to assume the Travis build will succeed when this is merged into master. If not, we'll fix it.

chrisr3 commented 7 years ago

Thanks for merging this, although the "exception code path" is rather hard to follow now. I'm not 100% certain how this call-stack unwinding mechanism works, but it looks we'd need to install a new "ignore exceptions" checkpoint before invoking dispatchUncaughtException() before my uncaughtException() function would be guaranteed to return in all cases. And unfortunately, such a checkpoint would seem to need to be implemented in assembler across multiple architectures!

Ideally, we'd like my new THREAD_RESOURCE0 block to execute and then return to allow the original THREAD_RESOURCE0 block to continue executing from where it left off.

dicej commented 6 years ago

Yeah, it could definitely be refined. I'll take another look when I have a chance. If you look for uses of vmRun in the code, you can see examples of how to prevent a thread from unwinding past a given point. You can think of vmRun as a way to catch exceptions and prevent the stack from unwinding further.

THREAD_RESOURCE0, on the other hand, is intended to be used to temporarily interrupt stack unwinding so some code can be run before the unwind is resumed. I do think a direct call to vmRun might be more appropriate in this case, but I haven't had time yet to think it through.