So there I was, planning to just fix one little bug: Thread.holdsLock
and Thread.yield were missing for the Android class library. Easy
enough, right? So, I added a test, got it passing, and figured I'd go
ahead and run ci.sh with all three class libraries. Big mistake.
Here's the stuff I found:
* minor inconsistency in README.md about OpenSSL version
* untested, broken Class.getEnclosingMethod (reported by Josh)
* JNI test failed for tails=true Android build
* Runtime.nativeExit missing for Android build
* obsolete assertion in CallEvent broke tails=true Android build
* obsolete superclass field offset padding broke bootimage=true Android build
* runtime annotation parsing broke bootimage=true Android build
(because we couldn't modify Addendum.annotationTable for classes in
the heap image)
* ci.sh tried building with both android=... and openjdk=..., which
the makefile rightfully balked at
Sorry this is all in a single commit; I didn't expect so many
unrelated issues, and I'm too lazy to break them apart.
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.
There's more work to do to derive all the properties of a given class
from its code source (e.g. JAR file), but this at least ensures that
ClassLoader.getPackage will actually return something non-null when
appropriate.
An inner class has two sets of modifier flags: one is declared in the
usual place in the class file and the other is part of the
InnerClasses attribute. Not only is that redundant, but they can
contradict, and the VM can't just pick one and roll with it. Instead,
Class.getModifiers must return the InnerClasses version, whereas
reflection must check the top-level version. So even if
Class.getModifiers says the class is protected, it might still be
public for the purpose of reflection depending on what the
InnerClasses attribute says. Crazy? Yes.
Android's class library uses this to find out whether the VM supports
compareAndSwapLong natively. Avian does on all platforms, so we just
return true.
Most of these regressions were simply due to testing a lot more stuff,
esp. annotations and reflection, revealing holes in the Android
compatibility code. There are still some holes, but at least the
suite is passing (except for a fragile test in Serialize.java which I
will open an issue for).
Sorry this is such a big commit; there was more to address than I
initially expected.
This mainly involved reworking the makefile to avoid conflating
Darwin/ARM builds with iOS, since we may also want to build for the
iOS Simulator, which is i386.
Note that I was only able to test this on the Simulator, since I don't
have a real iOS device to test with. Sorry if I broke something; if
so, please fix it :)
Previously, I used a shell script to extract modification date ranges
from the Git history, but that was complicated and unreliable, so now
every file just gets the same year range in its copyright header. If
someone needs to know when a specific file was modified and by whom,
they can look at the Git history themselves; no need to include it
redundantly in the header.