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.
Method.invoke should initialize its class before invoking the method,
throwing an ExceptionInInitializerError if it fails, without wrapping
said error in an InvocationTargetException.
Also, we must initialize ExceptionInInitializerError.exception when
throwing instances from the VM, since OpenJDK's
ExceptionInInitializerError.getCause uses the exception field, not the
cause field.
Inner classes can have inner classes, but getDeclaredClasses() is
supposed to list *only* the immediate inner classes.
Example: if class Reflection contains a class Hello that contains
a class World, Reflection.class.getDeclaredClasses() must not
include World in its result.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
We should pass the method of the original interface to the
InvocationHandler, not the method of the interface.
That way, proxy instances of annotations will have easy access to
the default values.
This happens to be compatible with the way Oracle Java does it, too.
To accomplish our goal, we keep a global map between proxy classes and
Method references and assign the appropriate list to a field of the
Proxy subclass. This means that we now have to call the super-class
constructor in the generated constructor (which is the correct thing to
do anyway... ;-)).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Proxies implement interfaces whose methods *must* be public, as per the
specification of the Java language.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When the class whose field is to be inspected has no annotations at all,
at least my javac here (1.6.0_51 on MacOSX) does not produce any class
addendum.
Therefore, let's verify that the addendum is not null before proceeding.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
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.
This mainly moves several sun.misc.Unsafe method implementations from
classpath-openjdk.cpp to builtin.cpp so that the Avian and Android
builds can use them.
It also replaces FinalizerReference.finalizeAllEnqueued with a no-op,
since the real implementations assumes too much about how the VM
handles (or delegates) finalization.
Java requires that NaNs be converted to zero and that numbers at or
beyond the limits of integer representation be clamped to the largest
or smallest value that can be represented, respectively.
Our implementation uses Object.wait(long) to implement Thread.sleep,
which had the side effect of interpreting zero as infinity. However,
for Thread.sleep, zero just means zero. I assume that doesn't mean
"don't sleep at all", though, or else the app wouldn't have called
Thread.sleep in the first place, so this patch sleeps for one
millisecond when zero is passed -- just enough to yield the processor
for a bit. Thread.yield might be a better choice in this case, but I
assume the app would have called that directly if that's what it
wanted.
We were not properly converting dots to slashes internally for package names
and we did not properly handle Method.getAnnotations and
Method.getAnnotation(Class<T>) on methods without any annotations.
Added some tests to cover these cases.
We now properly forward the errno value from the child when execvp()
fails, which the parent then uses to for the errno message as well as
including the failed command's name in the message.
We must throw an AbstractMethodError when such a call is executed (not
when the call is compiled), so we compile this case as a call to a
thunk which throws such an error.
OpenJDK's java.lang.ClassLoader.getResource makes use of
sun.misc.Launcher to load bootstrap resources, which is not
appropriate for the Avian build, so we override it to ensure we get
the behavior we want.
This test covers the case where a local stack slot is first used to
store an object reference and later to store a subroutine return
address. Unfortunately, this confuses the VM's stack mapping code;
I'll be working on a fix for that next.
The new test requires generating bytecode from scratch, since there's
no reliable way to get javac to generate the code we want. Since we
already had primitive bytecode construction code in Proxy.java, I
factored it out so we can reuse it in Subroutine.java.
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
The main change here is to use a lazily-populated vector to associate
runtime data with classes instead of referencing them directly from
the class which requires updating immutable references in the heap
image. The other changes employ other strategies to avoid trying to
update immutable references.
The first bug affected POSIX systems: if the app never called
Process.waitFor, we'd never call waitpid on the child and thus leak a
zombie process. This patch ensures that we always call waitpid by
spawning a thread to handle it.
The second bug affected Windows systems: we weren't closing the
child's ends of the stdin, stdout, and stderr pipes after process
creation, which lead to us blocking forever while reading from the
child's stdout or stderr.
Rather than try to support mixing Avian's core classes with those of
an external class library -- which necessitates adding a lot of stub
methods which throw UnsupportedOperationExceptions, among other
comprimises -- we're looking to support such external class libraries
in their unmodified forms. The latter strategy has already proven
successful with OpenJDK's class library. Thus, this commit removes
the stub methods, etc., which not only cleans up the code but avoids
misleading application developers as to what classes and methods
Avian's built-in class library supports.
The main changes in this commit ensure that we don't hold the global
class lock when doing class resolution using application-defined
classloaders. Such classloaders may do their own locking (in fact,
it's almost certain), making deadlock likely when mixed with VM-level
locking in various orders.
Other changes include a fix to avoid overflow when waiting for
extremely long intervals and a GC root stack mapping bug.
The biggest change in this commit is to split the system classloader
into two: one for boot classes (e.g. java.lang.*) and another for
application classes. This is necessary to make OpenJDK's security
checks happy.
The rest of the changes include bugfixes and additional JVM method
implementations in classpath-openjdk.cpp.
Whereas the GNU Classpath port used the strategy of patching Classpath
with core classes from Avian so as to minimize changes to the VM, this
port uses the opposite strategy: abstract and isolate
classpath-specific features in the VM similar to how we abstract away
platform-specific features in system.h. This allows us to use an
unmodified copy of OpenJDK's class library, including its core classes
and augmented by a few VM-specific classes in the "avian" package.
In order to facilitate making the VM compatible with multiple class
libraries, it's useful to separate the VM-specific representation of
these classes from the library implementations. This commit
introduces VMClass, VMField, and VMMethod for that purpose.