From 5d5a18c482283dcd327c342cde7a04050c901691 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 16:49:45 -0700 Subject: [PATCH 1/3] set Thread::exception to null before creating ExceptionInInitializerError If we don't do this, the VM will crash when it tries to create a stack trace for the error because makeObjectArray will return null immediately when it sees there is a pending exception. --- src/machine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/machine.cpp b/src/machine.cpp index 98835556bf..5614a4ccb1 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3436,8 +3436,10 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { + object exception = t->exception; + t->exception = 0; t->exception = makeThrowable - (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); + (t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; @@ -3882,6 +3884,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker) virtual bool visit(Processor::StackWalker* walker) { if (trace == 0) { trace = makeObjectArray(t, walker->count()); + vm_assert(t, trace); } object e = makeTraceElement(t, walker->method(), walker->ip()); From 857dcd13e7b5113178ea615f57f05fac87d6466b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 18:08:52 -0700 Subject: [PATCH 2/3] fix 64-bit constant comparisons on 32-bit platforms --- src/compiler.cpp | 14 +++++++++++--- test/Longs.java | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 23778520d6..1a96292b96 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4741,9 +4741,17 @@ class BranchEvent: public Event { if (not unreachable(this)) { if (firstConstant and secondConstant) { - if (shouldJump(c, type, size, firstConstant->value->value(), - secondConstant->value->value())) - { + int64_t firstValue = firstConstant->value->value(); + int64_t secondValue = secondConstant->value->value(); + + if (size > BytesPerWord) { + firstValue |= findConstantSite + (c, first->nextWord)->value->value() << 32; + secondValue |= findConstantSite + (c, second->nextWord)->value->value() << 32; + } + + if (shouldJump(c, type, size, firstValue, secondValue)) { apply(c, Jump, BytesPerWord, address->source, address->source); } } else { diff --git a/test/Longs.java b/test/Longs.java index 8c34fddce9..9beaf8a996 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -60,6 +60,11 @@ public class Longs { } public static void main(String[] args) throws Exception { + { long a = 0x1FFFFFFFFL; + long b = -1; + expect(a != b); + } + expect(Math.abs(-123L) == 123L); expect(readLongFrom(new java.io.InputStream() { From 2e86f0ac5727a856e61138ed94334ad29d8d10cd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 19:00:23 -0700 Subject: [PATCH 3/3] fix race condition leading to deadlock on exit There is a delay between when we tell the OS to start a thread and when it actually starts, and during that time a thread might mistakenly think it was the last to exit, try to shut down the VM, and then block in joinAll when it finds it wasn't the last one after all. The solution is to increment Machine::liveCount and add the new thread to the process tree before starting it -- all while holding Machine::stateLock for atomicity. This helps guarantee that when liveCount is one, we can be sure there's really only one thread running or staged to run. --- src/machine.cpp | 9 +++++---- src/machine.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 5614a4ccb1..1fade5edbe 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2258,7 +2258,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): vtable(&(m->jniEnvVTable)), m(m), parent(parent), - peer((parent ? parent->child : 0)), + peer(0), child(0), waitNext(0), state(NoState), @@ -2331,9 +2331,6 @@ Thread::init() javaThread = m->classpath->makeThread(this, 0); threadPeer(this, javaThread) = reinterpret_cast(this); - } else { - peer = parent->child; - parent->child = this; } expect(this, m->system->success(m->system->make(&lock))); @@ -2538,6 +2535,7 @@ enter(Thread* t, Thread::State s) -- t->m->daemonCount; } } + t->state = s; t->m->stateLock->notifyAll(t->systemThread); @@ -3739,7 +3737,10 @@ collect(Thread* t, Heap::CollectionType type) m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread); + addThread(t, m->finalizeThread); + if (not startThread(t, m->finalizeThread)) { + removeThread(t, m->finalizeThread); m->finalizeThread = 0; } } diff --git a/src/machine.h b/src/machine.h index 3333cb084a..872416b374 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1753,14 +1753,45 @@ startThread(Thread* t, Thread* p) return t->m->system->success(t->m->system->start(&(p->runnable))); } +inline void +addThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::NoState); + + p->state = Thread::IdleState; + ++ t->m->liveCount; + + p->peer = p->parent->child; + p->parent->child = p; +} + +inline void +removeThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::IdleState); + + -- t->m->liveCount; + + t->m->stateLock->notifyAll(t->systemThread); + + p->parent->child = p->peer; +} + inline Thread* startThread(Thread* t, object javaThread) { Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + addThread(t, p); + if (startThread(t, p)) { return p; } else { + removeThread(t, p); return 0; } } @@ -1791,6 +1822,8 @@ attachThread(Machine* m, bool daemon) Thread* t = m->processor->makeThread(m, 0, m->rootThread); m->system->attach(&(t->runnable)); + addThread(t, t); + enter(t, Thread::ActiveState); t->javaThread = m->classpath->makeThread(t, m->rootThread);