The problem (which we've only been able to reproduce consistently with
the openjdk-src process=interpret build on Linux virtual machines) was
a race condition during VM shutdown. Thread "A" would exit, see there
were other threads still running and thus enter ZombieState, which
involves acquiring and releasing a lock using RawMonitorResource.
Then the last thread (thread "B") would exit, wait for thread "A" to
release the lock, then shut down the VM, freeing all memory. However,
thread "A" writes to its Thread object one last time after releasing
the lock (in ~Resource, the destructor of the superclass of
RawMonitorResource, which sets Thread::resource). If thread "B" frees
that Thread before ~Resource runs, we end up writing to freed memory.
Thus, we need to update Thread::resource before releasing the lock.
Apparently C++ destructors run in order from most derived to least
derived, which is not what we want here. My solution to split
Resource into two classes, one that has no destructor and another that
extends it (called AutoResource) which does hafe a destructor. Now
all the classes which used to extend Resource extend AutoResource,
except for RawMonitorResource, which extends Resource directly so it
can control the order of operations.
This allows them to be shared between the Avian and Android class
library builds.
This commit also disables the URL test in Misc.java on Android, since
it's known to fail, and we still want to know whether the other tests
pass.
This was causing crashes on 32-bit OS X continuations=true builds.
There were two important differences between vmInvoke and
vmJumpAndInvoke: (1) vmInvoke expects its stack to be aligned on
entry, modulo the return address whereas the stack argument to
vmJumpAndInvoke is aligned without allowing for the return address,
and (2) vmInvoke pushes EBP before doing its frame allocation, whereas
vmJumpAndInvoke did not take that into account. So in order for
vmJumpAndInvoke to allocate the exact same frame size that vmInvoke
would have when calling the same method, it needed to add an extra two
words beyond what it was already allocating.
Aside from alignment concerns, the code is not particularly sensitive
to vmJumpAndInvoke allocating a different frame size than vmInvoke,
since we store the frame pointer in a "thread local" variable:
// remember this stack position, since we won't be able to rely on
// %rbp being restored when the call returns
movl 8(%ebp),%eax
movl %esp,TARGET_THREAD_SCRATCH(%eax)
...
GLOBAL(vmInvoke_returnAddress):
// restore stack pointer
movl TARGET_THREAD_SCRATCH(%ebx),%esp
My original patch makes an equivalent change for the 64-bit changes,
but I'll leave that for after we release 1.0 since we're in
bugfix-only mode right now
This was a bug, wherein upon throwing an exception, we would try to
allocate memory for the message - all while holding a critical
reference to the jbyteArray representing the exception string. This
caused an expect to fail in allocate3.
This ensures that all tests pass when Avian is built with an
openjdk=$path option such that $path points to either OpenJDK 7 or 8.
Note that I have not yet tried using the openjdk-src option with
OpenJDK 8. I'll work on that next.
617bd85 broke the Android build by creating an unresolvable
order-of-operations bug in classpath-android.cpp's
MyClasspath::preBoot method.
The problem is that, while JNIEnv::FindClass is supposed to initialize
the class that it finds, this causes JniConstants::init to indirectly
invoke native methods which are not registered until JNI_OnLoad is
called (which happens after JniConstants::init is called). However,
if we call JNI_OnLoad first, that causes methods to be invoked which
rely on JniConstants::init having already been run.
I haven't checked to see how Dalvik handles this, but I don't see any
way around the problem besides disabling initialization by
JNIEnv::FindClass until the preBoot phase is complete. Moreover, it's
dangerous to allow Java code to be invoked so early anyway, since the
VM is not yet fully initialized.
For some reason, running Avian under the SVN version of Valgrind
caused mmap to fail, which caused tryAllocateExecutable to return a
null pointer, which led to a non-obvious crash later on. Adding an
expect to check the result immediately will at least make it obvious
what went wrong.
bb86500 was a step in the right direction, but there was a bug that
caused Type_pad fields to be inserted between every other field in for
a derived class when type-maps.cpp was generated, and this led to
miscompilation of e.g. Android's
java.lang.reflect.Constructor.getModifiers.
We should define EXPORT to be __declspec(dllexport) on Windows
regardless of architecture, not just non-x86_64 arches. This fixes
errors to to embedded JAVA_HOME files not being found in openjdk-src
builds, e.g. lib/currency.data.
Although the JNI reference documentation does not mention it,
FindClass should initialize the class before it returns it. That's
what HotSpot does, and that's what we have to do too.
In particular, OpenJDK's
Java_java_net_Inet6AddressImpl_lookupAllHostAddr relies on
Inet6Address's static initializer being run when it is resolved using
FindClass, or else it will crash.