Method.invoke must throw an IllegalArgumentException if it receives
the wrong number or types of arguments, and since this isn't done by
the OpenJDK class library, we must do it in the VM.
This library is placed in the xawt subdirectory of jre/lib/$arch on
POSIX systems, so it isn't found automatically when third-party
libraries which depend on it are loaded. The simplest way to ensure
that it's found seems to be to just load it when the VM starts up.
The original stub implementation just echoed back its argument, but
that confused URLClassLoader when dealing with sealed JARs --
returning a non-null value for a non-system class from
JVM_GetSystemPackage made URLClassloader think it had already loaded a
class from a package which was supposed to be sealed, resulting in
SecurityExceptions which ultimately triggered NoClassDefFoundErrors.
The solution is to only return non-null values for actual system
classes.
We weren't wrapping exceptions thrown by invoked methods in
InvocationTargetExceptions in JVM_InvokeMethod or
JVM_NewInstanceFromConstructor. Also, JVM_GetCallerClass is supposed
to ignore Method.invoke frames when walking the stack.
The existing code did not handle static field lookups for
synchronization on 32-bit systems, which is necessary because such
systems generally don't support atomic operations on 64-bit values.
set java.vm.version based on makefile version=
in order to display relevant OpenJDK -version information.
Signed-off-by: Matthias Klose <doko@ubuntu.com>
Signed-off-by: Xerxes Rånby <xerxes@zafena.se>
Some apps refuse to run if Runtime.maxMemory returns a value that's
"too small", so our stub implementation returning zero was not
sufficient. Now we return the actual heap size limit in bytes.
sun.misc.Launcher has its own idea about what the application
classloader should be, but we need to override it with the system
classloader created by the VM. This is achieved by running
Launcher.getLauncher (which has the side effect of setting
Thread.contextClassLoader) and then overriding it.
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.
OpenJDK 7 has refactored this code relative to OpenJDK 6, and now
FontManager is an interface, with SunFontManager providing a (partial)
implementation.
On the ARM platform, Avian compiled to use OpenJDK gets this error on
startup:
java/lang/UnsatisfiedLinkError: no zip in java.library.path
at java/lang/ClassLoader.loadLibrary (line 1860)
at java/lang/Runtime.loadLibrary0 (line 845)
at java/lang/System.loadLibrary (line 1084)
at java/lang/System.initializeSystemClass (line 1145)
Using strace shows why:
[pid 22431]
stat64("/usr/lib/jvm/java-7-openjdk-armhf/jre/lib/i386/libzip.so",
0xbee377e0) = -1 ENOENT (No such file or directory)
The attached patch uses "arm" instead of "i386" in that path. This fixes the
problem.
sun.misc.Unsafe now has two native getByte methods: one which takes a
long and another which takes an Object and a long. Thus, we need to
decorate each version with its parameter signature so we don't
accidentally call the wrong one at runtime.
As of the latest code from the jdk7u-dev Mercurial repository,
java.lang.String no longer has offset or length fields. Instead, the
content fits exactly into the backing char array, so offset is
implicitly zero and length is the length of the array. The VM
previously relied on those fields being present, whereas this commit
handles the case where they are not.
In addition, I've made some changes to openjdk-src.mk to ensure that
we can build against both a stock OpenJDK 7 and an IcedTea-patched
version.
The JRE lib dir for OpenJDK 7 on OS X seems to be just "lib", not
e.g. "lib/amd64" by default, so we use that now. Also, the default
library compatibility version for libjvm.dylib is 0.0.0, but OpenJDK
wants 1.0.0, so we set it explicitly.
The bug here is that when a thread exits and becomes a "zombie", the
OS resources associated with it are not necessarily released until we
actually join and dispose of that thread. Since that only happens
during garbage collection, and collection normally only happens in
response to heap memory pressure, there's no guarantee that we'll GC
frequently enough to clean up zombies promptly and avoid running out
of resources.
The solution is to force a GC whenever we start a new thread and there
are at least N zombies waiting to be disposed, where N=16 for now.
We never define atomicCompareAndSwap64 for ARM or PowerPC, and
apparently only very recent ARM chips support it, so we must fall back
to synchronization-based emulation.
There were a couple of problems with the Avian_sun_misc_Unsafe_park
implementation in classpath-openjdk.cpp. First, the wait time should
be interpreted as milliseconds if absolute, but as nanoseconds
otherwise, whereas we were treating it as milliseconds in both cases.
Second, there was no mechanism to exit the while loop after the
specified time; the only way we could exit was via an unpark or
interrupt.
If we fail to resolve a given class (e.g. due to ProGuard obfuscating
or eliminating it), just move on to the next one rather than return
immediately. Otherwise, we may miss intercepting methods of classes
we can resolve.
sun.font.FontManager.initIDs is a native method defined in
libfontmanager.so, yet there seems to be no mechanism in OpenJDK's
class library to actually load that library, so we lazily load it
before trying to resolve the method.
Internally, the VM augments the method tables for abstract classes
with any inherited abstract methods to make code simpler elsewhere,
but that means we can't use that table to construct the result of
Class.getDeclaredMethods since it would include methods not actually
declared in the class. This commit ensures that we preserve and use
the original, un-augmented table for that purpose.
The result of Class.getInterfaces should not include interfaces
declared to be implemented/extended by superclasses/superinterfaces,
only those declared by the class itself. This is important because it
influences how java.io.ObjectStreamClass calculates serial version
IDs.
This includes a proper implementation of JVM_ActiveProcessorCount, as
well as JVM_SetLength and JVM_NewMultiArray. Also, we now accept up
to JNI_VERSION_1_6 in JVM_IsSupportedJNIVersion.
The main changes here are:
* fixes for runtime annotation support
* proper support for runtime generic type introspection
* throw NoClassDefFoundErrors instead of ClassNotFoundExceptions
where appropriate
This primarily required additions to classpath-openjdk.cpp to
intercept ZipFile, ZipEntry, and JarFile native methods to consult
embedded encryption policy jars when required.
The VM uses Integer and Long instances internally to wrap the results
of dynamic method invocations, but Method.invoke should use the
correct, specific type for the primitive (e.g. Character for char).
This rather large commit modifies the VM to use non-local returns to
throw exceptions instead of simply setting Thread::exception and
returning frame-by-frame as it used to. This has several benefits:
* Functions no longer need to check Thread::exception after each call
which might throw an exception (which would be especially tedious
and error-prone now that any function which allocates objects
directly or indirectly might throw an OutOfMemoryError)
* There's no need to audit the code for calls to functions which
previously did not throw exceptions but later do
* Performance should be improved slightly due to both the reduced
need for conditionals and because undwinding now occurs in a single
jump instead of a series of returns
The main disadvantages are:
* Slightly higher overhead for entering and leaving the VM via the
JNI and JDK methods
* Non-local returns can make the code harder to read
* We must be careful to register destructors for stack-allocated
resources with the Thread so they can be called prior to a
non-local return
The non-local return implementation is similar to setjmp/longjmp,
except it uses continuation-passing style to avoid the need for
cooperation from the C/C++ compiler. Native C++ exceptions would have
also been an option, but that would introduce a dependence on
libstdc++, which we're trying to avoid for portability reasons.
Finally, this commit ensures that the VM throws an OutOfMemoryError
instead of aborting when it reaches its memory ceiling. Currently, we
treat the ceiling as a soft limit and temporarily exceed it as
necessary to allow garbage collection and certain internal allocations
to succeed, but refuse to allocate any Java objects until the heap
size drops back below the ceiling.
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.
This mainly involves some makefile ugliness to work around bugs in the
native Windows OpenJDK code involving conflicting static and
not-static declarations which GCC 4.0 and later justifiably reject but
MSVC tolerates.
* add libnet.so and libnio.so to built-in libraries for openjdk-src build
* implement sun.misc.Unsafe.park/unpark
* implement JVM_SetClassSigners/JVM_GetClassSigners
* etc.
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.
All the tests are passing for openjdk-src builds, but the non-src
openjdk build is crashing and there's trouble loading time zone info
from the embedded java.home directory.
This allows OpenJDK to access time zone data which is normally found
under java.home, but which we must embed in the executable itself to
create a self-contained build. The VM intercepts various file
operations, looking for paths which start with a prefix specified by
the avian.embed.prefix property and redirecting those operations to an
embedded JAR.
For example, if avian.embed.prefix is "/avian-embedded", and code
calls File.exists() with a path of
"/avian-embedded/javahomeJar/foo.txt", the VM looks for a function
named javahomeJar via dlsym, calls the function to find the memory
region containing the embeded JAR, and finally consults the JAR to see
if the file "foo.txt" exists.
sun.misc.Unsafe.getUnsafe expects a null result if the class loader is
the boot classloader and will throw a SecurityException otherwise
(whereas it should really be checking both for null and comparing
against the system classloader). However, just returning null
whenever the loader is the boot loader can cause trouble for embedded
apps which put everything in the boot loader, including application
resources.
Therefore, we only return null if it's the boot loader and we're being
called from Unsafe.getUnsafe.
As described in readme.txt, a standalone OpenJDK build embeds all
libraries, classes, and other files needed at runtime in the resulting
binary, eliminating dependencies on external resources.
We now consult the JAVA_HOME environment variable to determine where
to find the system library JARs and SOs. Ultimately, we'll want to
support self-contained build, but this allows Avian to behave like a
conventional libjvm.so.
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.