scalac may emit a ldc followed by an i2c, whereas javac does the
conversion (including zero extension if necessary) at compile time.
This commit ensures we handle the i2c case properly.
Per https://github.com/ReadyTalk/avian/issues/53, Avian should build
against a standard AOSP checkout, which means we should look for
subprojects in the directories the repo utility would place them.
If sun.java.command or sun.java.launcher are set, then the VM is being
loaded from e.g. libjvm.so, not as a stand-alone executable. This
commit allows libjvm.dylib to be used with OpenJDK's java command on OS
X.
The OpenJDK library wants to track and run the shutdown hooks itself
rather than let the VM do it, so we need to tell it when we're
exiting.
Also, in machine.cpp we need to use only the modifiers specified in
the InnerClasses attribute for inner classes rather than OR them with
the flags given at the top level of the class file.
scalac may generate a ldc followed by an l2i, whereas javac always
seems to condense this into a single ldc_w. The former exposed a bug
in the JIT compiler which we never hit with javac-generated bytecode.
This fixes a couple of tests in the Scala test suite
(run/reflection-modulemirror-toplevel-badpath.scala and
run/reflection-constructormirror-nested-good.scala).
This is necessary to ensure that new threads do not start while we're
shutting down (except for the ones that we start to run the shutdown
hooks), and that the shutdown hook threads can be safely started (it
is not safe to start threads from e.g. an idle state, and an assertion
will fail if we do).
This ensures that, if an exception is thrown later but before the
method has been fully compiled, we will know exactly how much memory
to free. Previously, we would abort when trying to free the wrong
amount due to an assertion failure.
It's amazing to me that ebp and esp have been swapped for over three
years without anybody noticing. It was dumb luck that the Trace test
(which is designed to catch just such a thing) happened to fail when I
ran the whole suite, and further investigation revealed that it was
failing maybe five percent of the times it was run. Now we know why.
Timezone code was broken in the Android class library bootimage build
because the code we use to intercept loading the tzdata file wasn't
working. The reason is have no way of intercepting static methods at
runtime in the bootimage build without telling the bootimage-generator
we're going to do it ahead of time. So now we do tell it so.
This commit also removes the need to intercept Thread methods since we
can update Thread.vmThread in VMThread.create instead.
In order for a thread to enter the "exclusive" state such that no
other threads are active in the VM, it must wait for all active
threads to enter the "idle" state. In order for this to happen in a
timely manner, threads must check frequently to see if a thread is
waiting to enter the exclusive state. These checks happen at every
memory allocation, wait, sleep, native call, etc. However, if a
thread is in a busy loop that does none of those things, it will block
any other thread from entering that state.
The proper way to address this is to detect such loops (or tail
recursion in tail-call-optimized builds) at compile or interpret time
and insert explicit checks. This hasn't been a high priority thus
far, though, since we had yet to encounter such code in the wild.
Now, however, we find that scala.concurrent.forkjoin.ForkJoinPool.scan
(and possibly some versions of java.util.concurrent.ForkJoinPool.scan,
on which we assume the former is based) has just such a loop.
Fortunately, that loop calls Unsafe.getObjectVolatile, which the VM
implements and thus can treat as a checkpoint. That's the workaround
we use in this patch.
Setting this property (e.g. -Davian.trace.port=5555) will cause the VM
to start an extra daemon thread which listens on the specified TCP
port for incoming connections and dumps stack traces for all running
threads to that socket. You can retrieve that dump using e.g. netcat:
nc localhost 5555
Objects which are eligable for finalization must be retained until
after their finalize methods are called. However, the VM must
determine the entire set of such objects before retaining any of them;
otherwise the process of retaining a given object may cause others to
become reachable and thus be considered ineligible for finalization
even though they are only reachable via other finalizable objects.
The end result of this mistake is that only a few of the objects which
are finalizable will be recognized at each GC cycle, so it requires
many such cycles to find them all, and if new objects become
finalizable at a faster rate, the VM will never catch up and
eventually run out of memory.
This patch fixes the above mistake and also includes tuning to
minimize the need for GC in low memory situations.
In the OpenJDK library, ThreadGroup maintains an array of all Threads
in that group, so the VM must explicitly remove threads as they exit
or else neither they nor any objects they reference will be eligable
for GC.
The original goal was to minimize memory usage by garbage collecting
more frequently and more comprehensively as we got closer to the heap
limit. In practice, though, this just slowed the VM to a crawl as
memory pressure increased. If an app really wants to use a lot of
memory, the VM shouldn't penalize it aside from throwing an
OutOfMemoryError if it exceeds the limit.