Lots has changed since we forked Android's libcore, so merging the
latest upstream code has required extensive changes to the
Avian/Android port.
One big change is that we now use Avian's versions of
java.lang.Object, java.lang.Class, java.lang.ClassLoader, some
java.lang.reflect.* classes, etc. instead of the Android versions.
The main reason is that the Android versions have become very
Dex/Dalvik-specific, and since Avian is based on Java class files, not
dex archives, that code doesn't make sense here. This has the side
benefit that we can share more native code with classpath-avian.cpp
and reduce the amount of Java/C++ code duplication.
This function allows you to call native code such that any
SIGSEGV/SIGBUS/SIGFPE/EXC_ACCESS_VIOLATION/etc. raised by that code is
transformed into a Java exception and thrown by tryNative. Note that
this effectively results in a longjmp out of whatever function raised
the exception, so any C++ destructors or other cleanup code will not
be run.
Recent versions of jni.h such as the one provided by Debian Jessie's
OpenJDK define UNUSED in a way that conflicts with our definition and
usage, so we need to explicitly undefine it before redefining it to
avoid compiler noise.
Granted, this is weird - but this is what openjdk does. Therefore,
some code that is compiled for openjdk (say, protobufs) will treat
calls to Map.hashCode as interface calls instead of virtual calls, as
they would have previously been under avian's classpath.
Also note that this error caused avian to abort in findInterfaceMethod
rather than throw an AbstractMethodError or somesuch - but that's a
problem for another day.
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.
There was a test in Strings.java that assumed the default character
encoding was UTF-8, which is an invalid assumption on some platforms
(e.g. Windows). This modifies the test to specify the encoding
explicitly.
I also changed TreeMap to implement the "SortedMap" interface, like it should. Unfortanetly not all the code to implement the interface was there. Where it was simple I implemented the additional functions, in the case of headMap, tailMap, subMap we are currently just throwing an UnsupportedOperationException.
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.
The main idea is to make DatagramChannel and *SocketChannel behave in
a way that more closely matches the standard, e.g. allow binding
sockets to addresses without necessarily listening on those addresses
and accept null addresses where appropriate. It also avoids multiple
redundant DNS lookups.
This commit also implements CharBuffer and BindException, and adds the
Readable interface.
Since the function in question is the only one on the call stack above
the reset method, there's no need to invoke the captured continuation
-- we get the same effect by just returning normally, and it's more
efficient that way.
Turns out Function can do the jobs of both CallbackReceiver and
FunctionReceiver, so I've removed the latter two.
Also, shift and reset should work with a combination of types, not
just a single type, so I've expanded their generic signatures.
I've been told by knowledgeable people that it is impossible to
implement composable continuations (AKA delimited continuations AKA
shift/reset) in terms of call-with-current-continuation. Since I
don't yet understand why that is, I figured it would help my
understanding to attempt it and see how it fails.
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.
classpath-common.h's getDeclaringClass was trying to look up
non-existing classes, which led to an abort, and I don't even know
what Class.getDeclaredClasses was trying to do, but it was ugly and
wrong.
This is the simplest possible ConcurrentHashMap I could come up with
that works and is actually concurrent in the way one would expect.
It's pretty unconventional, being based on a persistent red-black
tree, and not particularly memory-efficient or cache-friendly. I
think this is a good place to start, though, and it should perform
reasonably well for most workloads. Patches for a more efficient
implementation are welcome!
I also implemented AtomicReferenceArray, since I was using it in my
first, naive attempt to implement ConcurrentHashMap.
I had to do a bit of refactoring, including moving some non-standard
stuff from java.util.Collections to avian.Data so I could make it
available to code outside the java.util package, which is why I had to
modify several unrelated files.
I had to implement a blocking queue for ExecutorCompletionService. LinkedBlockingQueue could be very easily extended right now to implement the java 7 LinkedBlockingDeque. Right now LinkedBlockingQueue just synchronizes and depends on LinkedList implementation. But I wrote a very complete unit test suite so we if we want to put a more concurrent design here, we have a complete test suite to verify against.# Please enter the commit message for your changes. Lines starting
We added a 4th state, so we have "Canceling and Canceled". We are in canceling state if we previously were running, and will not transition to canceled till after the interrupt has been sent. So at the end if we are not running, or already canceled, we will sleep, waiting for the interrupt to occur so we can be sure we handle it before we let the thread complete.
This also fixes a condition where we returned true on a cancel after a task has already been canceled
getDeclaredMethods was returning methods which were inherited from
interfaces but not (re)declared in the class itself, due to the VM's
internal use of VMClass.methodTable differing from its role in
reflection. For reflection, we must only include the declared
methods, not the inherited but un-redeclared ones.
Previously, we saved the original method table in
ClassAddendum.methodTable before creating a new one which contains
both declared and inherited methods. That wasted space, so this patch
replaces ClassAddendum.methodTable with
ClassAddendum.declaredMethodCount, which specifies how many of the
methods in VMClass.methodTable were declared in that class.
Alternatively, we could ensure that undeclared methods always have
their VMMethod.class_ field set to the declaring class instead of the
inheriting class. I tried this, but it led to subtle crashes in
interface method lookup. The rest of the VM relies not only on
VMClass.methodTable containing all inherited interface methods but
also that those methods point to the inheriting class, not the
declaring class. Changing those assumptions would be a much bigger
(and more dangerous in terms of regression potential) effort than I
care to take on right now. The solution I chose is a bit ugly, but
it's safe.
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.
This also changes ConcurrentLinkedQueue to implement the Queue interface, and just throw exceptions for operations which are not currently implemented.
This makes them available in all class libraries, not just the OpenJDK
library. Note that I've also removed the unecessary idle statements,
per ab4adef.
We were decrementing the "remaining" field twice for each byte read
using the no-arg read method, which resulted in available() returning
a value that was too small.