This makes heap dumps more useful since these classes are now refered
to by name instead of number.
This commit also adds a couple of utilities for parsing heap dumps:
PrintDump and DumpStats.
The primary change is to ensure we output a Mach-O file of appropriate
endianness when cross-compiling for an opposite-endian architecture.
Earlier versions of XCode's linker accepted files of either
endianness, reguardless of architecture, but later versions don't,
hence the change.
Previously, loading an arbitrary 32-bit constant required up to four
instructions (128 bytes), since we did so one byte at a time via
immediate-mode operations.
The preferred way to load constants on ARM is via PC-relative
addressing, but this is challenging because immediate memory offsets
are limited to 4096 bytes in either direction. We frequently need to
compile methods which are larger than 4096, or even 8192, bytes, so we
must intersperse code and data if we want to use PC-relative loads
everywhere.
This commit enables pervasive PC-relative loads by handling the
following cases:
1. Method is shorter than 4096 bytes: append data table to end
2. Method is longer than 4096 bytes, but no basic block is longer
than 4096 bytes: insert data tables as necessary after blocks, taking
care to minimize the total number of tables
3. Method is longer than 4096 bytes, and some blocks are longer than
4096 bytes: split large basic blocks and insert data tables as above
Previously, we waited until the next GC to do this, but that can be
too long for workloads which create a lot of short-lived threads but
don't do much allocation.
This requires adding LinkRegister to the list of reserved registers,
since it must be preserved in the thunk code generated by
compileDirectInvoke. An alternative would be to explicitly preserve
it in that special case, but that would complicate the code quite a
bit.
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.
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.
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.
We've been getting away with not doing this so far since our Java
calling convention matches the native calling convention concerning
where the return address is saved, so when our thunk calls native code
it gets saved for us automatically. However, there was still the
danger that a thread would interrupt another thread after the stack
pointer was saved to the thread field but before the native code was
called and try to get a stack trace, at which point it would try to
find the return address relative to that stack pointer and find
garbage instead. This commit ensures that we save the return address
before saving the stack pointer to avoid such a situation.
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.
A long time ago, I refactored the class initialization code in the VM,
but did not notice until today that it had caused the
process=interpret build to break on certain recursive initializations.
In particular, we were not always detecting when a thread recursively
tried to initialize a class it was already in the process of
initializing, leading to the mistaken assumption that another thread
was initializing it and that we should wait until it was done, in
which case we would wait forever.
This commit ensures that we always detect recursive initialization and
short-circuit it.
The shiftLeftC function in powerpc.cpp was miscompiling such shifts,
leading to crashes due to illegal instructions and other weirdness due
to instructions that meant something completely different. This
commit fixes that and adds a test to Longs.java to make sure it stays
fixed.
Previously, we risked segfaults by passing negative numbers to memcpy.
This commit also makes arraycopy throw an IndexOutOfBounds exception
instead of an ArrayStoreException if the specified offsets and lengths
would take us outside the bounds of one or both of the arrays, per the
Sun documentation.
If we catch the target thread in a virtual thunk when getting its
stack trace, we must assume its Thread::stack field is garbage and use
the register values instead. Previously, we treated these thunks as
any other native code, leading to crashes when we tried to use the
garbage pointer.
32MB was just slightly too large for PowerPC immediate call instructions
to span, and 16MB matches the JIT executable memory area we use in
compile.cpp.
compileDirectInvoke does some magic to optimize tail calls to native
methods which involves storing the return address (which we'll never
actually return to, since it's a tail call) in a thread-local field so
the thunk function can figure out which native method to look up at
runtime. Since this address will change when the boot image is
loaded, the boot image creation code needs to know about it.
callContinuation failed to call the correct continuation when feeding
it an exception due to a regression introduced with the
Thread.getStackTrace changes.
The new Thread::defaultHeap declaration has increased the offset of all
the fields following it.
This commit also makes vmInvoke_returnAddress global so it can be refered
to from compile.cpp.
It's not safe to use malloc from a signal handler, so we can't
allocate new memory when handling segfaults or Thread.getStackTrace
signals. Instead, we allocate a fixed-size backup heap for each
thread ahead of time and use it if there's no space left in the normal
heap pool. In the rare case that the backup heap isn't large enough,
we fall back to using a preallocated exception without a stack trace
as a last resort.
This function was broken in two different ways:
1. It only checked MyProcessor::thunks, not MyProcessor::bootThunks.
It needs to check both.
2. When checking MyProcessor::thunks, it used fields from
MyProcessor::bootThunks instead of from the same thunk collection.
This fixes both problems.
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
In Mac OS X, if a path contains a space, the path of the main executable
will contain a special URL-encoded character (%20 in this case). This
probably happens when any non-ASCII character is provided.
The fix is to use CFURLCreateStringByReplacingPercentEscapes which
creates a path that the POSIX API likes better.