From 2c4e229e6ed5090fef5b706108765ca88b977746 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 11 Jan 2010 08:31:01 -0700 Subject: [PATCH 01/18] convert forward slashes to back slashes in Windows paths --- classpath/java/io/File.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index da87db791e..c3fa42932f 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -24,7 +24,7 @@ public class File { public File(String path) { if (path == null) throw new NullPointerException(); - this.path = path; + this.path = normalize(path); } public File(String parent, String child) { @@ -35,6 +35,14 @@ public class File { this(parent.getPath() + FileSeparator + child); } + private static String normalize(String path) { + if ("\\".equals(FileSeparator)) { + return path.replace('/', '\\'); + } else { + return path; + } + } + public static native boolean rename(String old, String new_); public boolean renameTo(File newName) { From bdeb61fc9977b3d6897cf2b938dff55399db88ee Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 15 Jan 2010 08:25:06 -0700 Subject: [PATCH 02/18] fix grammar in readme.txt --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 2d4fd83c7e..78bad0048a 100644 --- a/readme.txt +++ b/readme.txt @@ -158,7 +158,7 @@ There's also a win64 repository for 64-bit builds: $ git clone git://oss.readytalk.com/win64.git -Building with Microsoft the Visual C++ Compiler +Building with the Microsoft Visual C++ Compiler ----------------------------------------------- You can also build using the MSVC compiler, which makes debugging with From 2868413b51960ff7fcc689f4a43d8f8d1bf90a14 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 27 Jan 2010 13:44:02 -0700 Subject: [PATCH 03/18] preserve exception classes from obfuscation in vm.pro We preserve from obfuscation by ProGuard any class of exception thrown from either the VM or native class library code. --- vm.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vm.pro b/vm.pro index 3ba4620c0e..98d92c15b2 100644 --- a/vm.pro +++ b/vm.pro @@ -32,10 +32,12 @@ # the VM may throw instances of the following: -keep public class avian.IncompatibleContinuationException +-keep public class java.lang.Exception -keep public class java.lang.RuntimeException -keep public class java.lang.IllegalStateException -keep public class java.lang.IllegalArgumentException -keep public class java.lang.IllegalMonitorStateException +-keep public class java.lang.IllegalThreadStateException -keep public class java.lang.ArrayIndexOutOfBoundsException -keep public class java.lang.ArrayStoreException -keep public class java.lang.NegativeArraySizeException @@ -51,6 +53,8 @@ -keep public class java.lang.OutOfMemoryError -keep public class java.lang.reflect.InvocationTargetException -keep public class java.io.IOException +-keep public class java.io.FileNotFoundException +-keep public class java.net.SocketException # ClassLoader.getSystemClassloader() depends on the existence of this class: From 45476eb591d927dbd4afde7a4d29e031139523ad Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 27 Jan 2010 17:46:04 -0700 Subject: [PATCH 04/18] fix handling of volatile longs and doubles on PowerPC We were miscompiling methods which contained getfield, getstatic, putfield, or putstatic instructions for volatile 64-bit primitives on 32-bit PowerPC due to not noticing that values in registers are clobbered across function calls. The solution is to create a separate Compiler::Operand instance for each object monitor reference before and after the function call to avoid confusing the compiler. To avoid duplicate entries in the constant pool, we add code look for and, if found, reuse any existing entry for the same constant. --- src/compile.cpp | 22 ++++++++++------------ test/Misc.java | 4 ++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 11bf8fcfcc..00fa33aa15 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1101,6 +1101,12 @@ class Frame { return c->promiseConstant(p, Compiler::ObjectType); } else { + for (PoolElement* e = context->objectPool; e; e = e->next) { + if (o == e->target) { + return c->address(e); + } + } + context->objectPool = new (context->zone.allocate(sizeof(PoolElement))) PoolElement(t, o, context->objectPool); @@ -3555,21 +3561,17 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } - Compiler::Operand* fieldOperand = 0; - if ((fieldFlags(t, field) & ACC_VOLATILE) and BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { - fieldOperand = frame->append(field); - c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), - fieldOperand); + frame->append(field)); } switch (fieldCode(t, field)) { @@ -3652,7 +3654,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), - fieldOperand); + frame->append(field)); } else { c->loadBarrier(); } @@ -4571,21 +4573,17 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, table = frame->popObject(); } - Compiler::Operand* fieldOperand = 0; - if (fieldFlags(t, field) & ACC_VOLATILE) { if (BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { - fieldOperand = frame->append(field); - c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), fieldOperand); + c->register_(t->arch->thread()), frame->append(field)); } else { c->storeStoreBarrier(); } @@ -4663,7 +4661,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (getThunk(t, releaseMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), fieldOperand); + c->register_(t->arch->thread()), frame->append(field)); } else { c->storeLoadBarrier(); } diff --git a/test/Misc.java b/test/Misc.java index 8795c9007b..5542ce5cfd 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -5,6 +5,8 @@ public class Misc { private static volatile int volatileStatic; + private static volatile long volatileStaticLong; + private final int NonStaticConstant = 42; private int gamma; @@ -131,6 +133,7 @@ public class Misc { beta = 42; alpha = 43; volatileStatic = 55; + volatileStaticLong = 9L; int e = beta; int f = alpha; m.volatileMember = 23; @@ -141,6 +144,7 @@ public class Misc { expect(alpha == 43); expect(m.gamma == 44); expect(volatileStatic == 55); + expect(volatileStaticLong == 9L); expect(m.volatileMember == 27); } From 8120bee4dc5f9ae2dec75a907778f1479ad398bd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 1 Feb 2010 17:56:09 -0700 Subject: [PATCH 05/18] reimplement Java object monitors to avoid running out of OS handles Due to SWT's nasty habit of creating a new object monitor for every task added to Display.asyncExec, we've found that, on Windows at least, we tend to run out of OS handles due to the large number of mutexes we create between garbage collections. One way to address this might be to trigger a GC when either the number of monitors created since the last GC exceeds a certain number or when the total number of monitors in the VM reaches a certain number. Both of these risk hurting performance, especially if they force major collections which would otherwise be infrequent. Also, it's hard to know what the values of such thresholds should be on a given system. Instead, we reimplement Java monitors using atomic compare-and-swap (CAS) and thread-specific native locks for blocking in the case of contention. This way, we can create an arbitrary number of monitors without creating any new native locks. The total number of native locks needed by the VM is bounded instead by the number of live threads plus a small constant. Note that if we ever add support for an architecture which does not support CAS, we'll need to provide a fallback monitor implementation. --- src/machine.cpp | 51 ++++---- src/machine.h | 316 +++++++++++++++++++++++++++++++++++++++++++++--- src/types.def | 12 ++ 3 files changed, 338 insertions(+), 41 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 8507e9c256..76953e480b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1808,17 +1808,13 @@ removeMonitor(Thread* t, object o) hash = objectHash(t, o); } - object p = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); - expect(t, p); + expect(t, m); if (DebugMonitors) { - fprintf(stderr, "dispose monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - hash); + fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); } - - static_cast(pointerValue(t, p))->dispose(); } void @@ -2185,9 +2181,11 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): parent(parent), peer((parent ? parent->child : 0)), child(0), + waitNext(0), state(NoState), criticalLevel(0), systemThread(0), + lock(0), javaThread(javaThread), exception(0), heapIndex(0), @@ -2201,6 +2199,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): backupHeap(0), backupHeapIndex(0), backupHeapSizeInWords(0), + waiting(false), tracing(false) #ifdef VM_STRESS , stress(false) @@ -2255,6 +2254,8 @@ Thread::init() parent->child = this; } + expect(this, m->system->success(m->system->make(&lock))); + if (javaThread == 0) { this->javaThread = makeJavaThread(this, parent); } @@ -2282,6 +2283,8 @@ Thread::exit() void Thread::dispose() { + lock->dispose(); + if (systemThread) { systemThread->dispose(); } @@ -3419,49 +3422,43 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) t->m->finalizers = f; } -System::Monitor* +object objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); - object p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (p) { + if (m) { if (DebugMonitors) { - fprintf(stderr, "found monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - objectHash(t, o)); + fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o)); } - return static_cast(pointerValue(t, p)); + return m; } else if (createNew) { PROTECT(t, o); ENTER(t, Thread::ExclusiveState); - p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (p) { + m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + if (m) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - objectHash(t, o)); + m, objectHash(t, o)); } - return static_cast(pointerValue(t, p)); + return m; } - System::Monitor* m; - System::Status s = t->m->system->make(&m); - expect(t, t->m->system->success(s)); + object head = makeMonitorNode(t, 0, 0); + object m = makeMonitor(t, 0, 0, 0, head, head, 0); + PROTECT(t, m); if (DebugMonitors) { - fprintf(stderr, "made monitor %p for object %x\n", - m, - objectHash(t, o)); + fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o)); } - p = makePointer(t, m); - hashMapInsert(t, t->m->monitorMap, o, p, objectHash); + hashMapInsert(t, t->m->monitorMap, o, m, objectHash); addFinalizer(t, o, removeMonitor); diff --git a/src/machine.h b/src/machine.h index fa8d99936d..24fe9ab70b 100644 --- a/src/machine.h +++ b/src/machine.h @@ -17,6 +17,7 @@ #include "finder.h" #include "processor.h" #include "constants.h" +#include "arch.h" #ifdef PLATFORM_WINDOWS # define JNICALL __stdcall @@ -1212,6 +1213,7 @@ class Machine { JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; unsigned heapPoolIndex; + unsigned recentMonitorCount; }; void @@ -1345,9 +1347,11 @@ class Thread { Thread* parent; Thread* peer; Thread* child; + Thread* waitNext; State state; unsigned criticalLevel; System::Thread* systemThread; + System::Monitor* lock; object javaThread; object exception; unsigned heapIndex; @@ -1360,6 +1364,7 @@ class Thread { uintptr_t* backupHeap; unsigned backupHeapIndex; unsigned backupHeapSizeInWords; + bool waiting; bool tracing; #ifdef VM_STRESS bool stress; @@ -2296,7 +2301,288 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); -System::Monitor* +inline bool +monitorTryAcquire(Thread* t, object monitor) +{ + if (monitorOwner(t, monitor) == t + or atomicCompareAndSwap + (reinterpret_cast(&monitorOwner(t, monitor)), 0, + reinterpret_cast(t))) + { + ++ monitorDepth(t, monitor); + return true; + } else { + return false; + } +} + +inline bool +atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, + object old, object new_) +{ + if (atomicCompareAndSwap(&cast(target, offset), + reinterpret_cast(old), + reinterpret_cast(new_))) + { + mark(t, target, offset); + return true; + } else { + return false; + } +} + +// The following two methods (monitorAtomicAppendAcquire and +// monitorAtomicPollAcquire) use the Michael and Scott Non-Blocking +// Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html + +inline void +monitorAtomicAppendAcquire(Thread* t, object monitor) +{ + PROTECT(t, monitor); + + object node = makeMonitorNode(t, t, 0); + + while (true) { + object tail = monitorAcquireTail(t, monitor); + + loadMemoryBarrier(); + + object next = monitorNodeNext(t, tail); + + loadMemoryBarrier(); + + if (tail == monitorAcquireTail(t, monitor)) { + if (next) { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, next); + } else if (atomicCompareAndSwapObject + (t, tail, MonitorNodeNext, 0, node)) + { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, node); + return; + } + } + } +} + +inline Thread* +monitorAtomicPollAcquire(Thread* t, object monitor, bool remove) +{ + while (true) { + object head = monitorAcquireHead(t, monitor); + + loadMemoryBarrier(); + + object tail = monitorAcquireTail(t, monitor); + + loadMemoryBarrier(); + + object next = monitorNodeNext(t, head); + + loadMemoryBarrier(); + + if (head == monitorAcquireHead(t, monitor)) { + if (head == tail) { + if (next) { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, next); + } else { + return 0; + } + } else { + Thread* value = static_cast(monitorNodeValue(t, next)); + if ((not remove) + or atomicCompareAndSwapObject + (t, monitor, MonitorAcquireHead, head, next)) + { + return value; + } + } + } + } +} + +inline void +monitorAcquire(Thread* t, object monitor) +{ + if (not monitorTryAcquire(t, monitor)) { + PROTECT(t, monitor); + + ACQUIRE(t, t->lock); + + monitorAtomicAppendAcquire(t, monitor); + + // note that we don't try to acquire the lock until we're first in + // line, both because it's fair and because we don't support + // removing elements from arbitrary positions in the queue + + while (not (t == monitorAtomicPollAcquire(t, monitor, false) + and atomicCompareAndSwap + (reinterpret_cast(&monitorOwner(t, monitor)), 0, + reinterpret_cast(t)))) + { + ENTER(t, Thread::IdleState); + + t->lock->wait(t->systemThread, 0); + } + + expect(t, t == monitorAtomicPollAcquire(t, monitor, true)); + + ++ monitorDepth(t, monitor); + } +} + +inline void +monitorRelease(Thread* t, object monitor) +{ + expect(t, monitorOwner(t, monitor) == t); + + if (-- monitorDepth(t, monitor) == 0) { + monitorOwner(t, monitor) = 0; + + storeLoadMemoryBarrier(); + + Thread* next = monitorAtomicPollAcquire(t, monitor, false); + + if (next) { + ACQUIRE(t, next->lock); + + next->lock->notify(t->systemThread); + } + } +} + +inline void +monitorAppendWait(Thread* t, object monitor) +{ + expect(t, not t->waiting); + expect(t, t->waitNext == 0); + + t->waiting = true; + + if (monitorWaitTail(t, monitor)) { + static_cast(monitorWaitTail(t, monitor))->waitNext = t; + } else { + monitorWaitHead(t, monitor) = t; + } + + monitorWaitTail(t, monitor) = t; +} + +inline void +monitorRemoveWait(Thread* t, object monitor) +{ + Thread* previous = 0; + for (Thread* current = static_cast(monitorWaitHead(t, monitor)); + current;) + { + if (t == current) { + if (current == monitorWaitHead(t, monitor)) { + monitorWaitHead(t, monitor) = t->waitNext; + } else { + previous->waitNext = t->waitNext; + } + + if (current == monitorWaitTail(t, monitor)) { + monitorWaitTail(t, monitor) = previous; + } + + t->waitNext = 0; + t->waiting = false; + + return; + } else { + previous = current; + current = current->waitNext; + } + } + + abort(t); +} + +inline bool +monitorWait(Thread* t, object monitor, int64_t time) +{ + expect(t, monitorOwner(t, monitor) == t); + + bool interrupted; + unsigned depth; + bool stillWaiting; + + PROTECT(t, monitor); + + { ACQUIRE(t, t->lock); + + monitorAppendWait(t, monitor); + + depth = monitorDepth(t, monitor); + monitorDepth(t, monitor) = 1; + + monitorRelease(t, monitor); + + ENTER(t, Thread::IdleState); + + interrupted = t->lock->wait(t->systemThread, time); + + stillWaiting = t->waiting; + } + + monitorAcquire(t, monitor); + + if (stillWaiting) { + monitorRemoveWait(t, monitor); + } + + monitorOwner(t, monitor) = t; + monitorDepth(t, monitor) = depth; + + return interrupted; +} + +inline Thread* +monitorPollWait(Thread* t, object monitor) +{ + Thread* next = static_cast(monitorWaitHead(t, monitor)); + + if (next) { + monitorWaitHead(t, monitor) = next->waitNext; + next->waitNext = 0; + if (next == monitorWaitTail(t, monitor)) { + monitorWaitTail(t, monitor) = 0; + } + } + + return next; +} + +inline bool +monitorNotify(Thread* t, object monitor) +{ + expect(t, monitorOwner(t, monitor) == t); + + Thread* next = monitorPollWait(t, monitor); + + if (next) { + ACQUIRE_RAW(t, next->lock); + + next->waiting = false; + + next->lock->notify(t->systemThread); + + return true; + } else { + return false; + } +} + +inline void +monitorNotifyAll(Thread* t, object monitor) +{ + while (monitorNotify(t, monitor)) { } +} + +object objectMonitor(Thread* t, object o, bool createNew); inline void @@ -2307,14 +2593,14 @@ acquire(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, true); + object m = objectMonitor(t, o, true); if (DebugMonitors) { fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } - acquire(t, m); + monitorAcquire(t, m); } inline void @@ -2325,14 +2611,14 @@ release(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } - release(t, m); + monitorRelease(t, m); } inline void @@ -2343,17 +2629,19 @@ wait(Thread* t, object o, int64_t milliseconds) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p waits %d millis on %p for %x\n", t, static_cast(milliseconds), m, hash); } - if (m and m->owner() == t->systemThread) { + if (m and monitorOwner(t, m) == t) { + PROTECT(t, m); + bool interrupted; { ENTER(t, Thread::IdleState); - interrupted = m->wait(t->systemThread, milliseconds); + interrupted = monitorWait(t, m, milliseconds); } if (interrupted) { @@ -2379,15 +2667,15 @@ notify(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies on %p for %x\n", t, m, hash); } - if (m and m->owner() == t->systemThread) { - m->notify(t->systemThread); + if (m and monitorOwner(t, m) == t) { + monitorNotify(t, m); } else { t->exception = makeIllegalMonitorStateException(t); } @@ -2396,15 +2684,15 @@ notify(Thread* t, object o) inline void notifyAll(Thread* t, object o) { - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies all on %p for %x\n", t, m, objectHash(t, o)); } - if (m and m->owner() == t->systemThread) { - m->notifyAll(t->systemThread); + if (m and monitorOwner(t, m) == t) { + monitorNotifyAll(t, m); } else { t->exception = makeIllegalMonitorStateException(t); } diff --git a/src/types.def b/src/types.def index 9a704c3b91..184df800a0 100644 --- a/src/types.def +++ b/src/types.def @@ -111,6 +111,18 @@ (object first) (object second)) +(type monitor + (void* owner) + (void* waitHead) + (void* waitTail) + (object acquireHead) + (object acquireTail) + (unsigned depth)) + +(type monitorNode + (void* value) + (object next)) + (type continuationContext (object next) (object before) From 5d781a0584068277b69022a53e6278fdc6dfb2ce Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Feb 2010 09:33:10 -0700 Subject: [PATCH 06/18] declare Long.MAX_VALUE and Long.MIN_VALUE as longs, not Longs --- classpath/java/lang/Long.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index 279a8220ed..c7c9767380 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -11,8 +11,8 @@ package java.lang; public final class Long extends Number implements Comparable { - public static final Long MIN_VALUE = -9223372036854775808l; - public static final Long MAX_VALUE = 9223372036854775807l; + public static final long MIN_VALUE = -9223372036854775808l; + public static final long MAX_VALUE = 9223372036854775807l; public static final Class TYPE = Class.forCanonicalName("J"); From 3bc37d6e2a7b7eb0f6e31dfa333d244f52e8c4bc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Feb 2010 11:37:08 -0700 Subject: [PATCH 07/18] fix encoding of single byte register-to-memory moves on x86_64 We need to prefix instructions of the form "mov R,M" with a REX byte when R is %spl, %bpl, %sil, or %dil. Such moves are unencodable on 32-bit x86, and, because of the order in which we pick registers, pretty rare on 64-bit systems, which is why this took so long to notice. --- src/x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index 4021c86e6d..2d4d3e55f7 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -518,7 +518,7 @@ void maybeRex(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) { - maybeRex(c, size, a->low, b->index, b->base, false); + maybeRex(c, size, a->low, b->index, b->base, size == 1 and (a->low & 4)); } void From e92674cb7337355dc4dd6317219010e5d1ce7e1c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Feb 2010 12:24:05 -0700 Subject: [PATCH 08/18] fix race condition in monitorWait We don't want to check Thread::waiting until we have re-acquired the monitor, since another thread might notify us between releasing Thread::lock and acquiring the monitor. --- src/machine.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/machine.h b/src/machine.h index 24fe9ab70b..441eecc6a0 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2508,7 +2508,6 @@ monitorWait(Thread* t, object monitor, int64_t time) bool interrupted; unsigned depth; - bool stillWaiting; PROTECT(t, monitor); @@ -2524,13 +2523,11 @@ monitorWait(Thread* t, object monitor, int64_t time) ENTER(t, Thread::IdleState); interrupted = t->lock->wait(t->systemThread, time); - - stillWaiting = t->waiting; } monitorAcquire(t, monitor); - if (stillWaiting) { + if (t->waiting) { monitorRemoveWait(t, monitor); } From 29309fb4149ec02f993f84ffe4675e95c98db832 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Feb 2010 12:26:09 -0700 Subject: [PATCH 09/18] update Thread field offsets to reflect recent additions Every time we add or remove fields to Thread, we need to update the assembly code to reflect the new offsets. --- src/compile-powerpc.S | 10 +++++----- src/continuations-x86.S | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index c90f16c625..8936899b53 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,11 +24,11 @@ # define GLOBAL(x) x #endif -#define THREAD_CONTINUATION 100 -#define THREAD_EXCEPTION 36 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 -#define THREAD_EXCEPTION_OFFSET 108 -#define THREAD_EXCEPTION_HANDLER 112 +#define THREAD_CONTINUATION 112 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 116 +#define THREAD_EXCEPTION_OFFSET 120 +#define THREAD_EXCEPTION_HANDLER 124 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/continuations-x86.S b/src/continuations-x86.S index 2151659ddf..aeee640388 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 176 -#define THREAD_EXCEPTION 64 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 184 -#define THREAD_EXCEPTION_OFFSET 192 -#define THREAD_EXCEPTION_HANDLER 200 +#define THREAD_CONTINUATION 192 +#define THREAD_EXCEPTION 80 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 200 +#define THREAD_EXCEPTION_OFFSET 208 +#define THREAD_EXCEPTION_HANDLER 216 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 100 -#define THREAD_EXCEPTION 36 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 -#define THREAD_EXCEPTION_OFFSET 108 -#define THREAD_EXCEPTION_HANDLER 112 +#define THREAD_CONTINUATION 108 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 112 +#define THREAD_EXCEPTION_OFFSET 116 +#define THREAD_EXCEPTION_HANDLER 120 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 From 48834be209c5a52dee883895dccfd85fe9bcf326 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Feb 2010 08:18:39 -0700 Subject: [PATCH 10/18] revert recent commits to reimplement Java object monitors We're seeing race conditions which occasionally lead to assertion failures and thus crashes, so I'm reverting these changes for now: 29309fb4149ec02f993f84ffe4675e95c98db832 e92674cb7337355dc4dd6317219010e5d1ce7e1c 8120bee4dc5f9ae2dec75a907778f1479ad398bd --- src/compile-powerpc.S | 10 +- src/continuations-x86.S | 20 +-- src/machine.cpp | 51 ++++--- src/machine.h | 313 ++-------------------------------------- src/types.def | 12 -- 5 files changed, 56 insertions(+), 350 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 8936899b53..c90f16c625 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,11 +24,11 @@ # define GLOBAL(x) x #endif -#define THREAD_CONTINUATION 112 -#define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 116 -#define THREAD_EXCEPTION_OFFSET 120 -#define THREAD_EXCEPTION_HANDLER 124 +#define THREAD_CONTINUATION 100 +#define THREAD_EXCEPTION 36 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 +#define THREAD_EXCEPTION_OFFSET 108 +#define THREAD_EXCEPTION_HANDLER 112 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/continuations-x86.S b/src/continuations-x86.S index aeee640388..2151659ddf 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 192 -#define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 200 -#define THREAD_EXCEPTION_OFFSET 208 -#define THREAD_EXCEPTION_HANDLER 216 +#define THREAD_CONTINUATION 176 +#define THREAD_EXCEPTION 64 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 184 +#define THREAD_EXCEPTION_OFFSET 192 +#define THREAD_EXCEPTION_HANDLER 200 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 108 -#define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 112 -#define THREAD_EXCEPTION_OFFSET 116 -#define THREAD_EXCEPTION_HANDLER 120 +#define THREAD_CONTINUATION 100 +#define THREAD_EXCEPTION 36 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 +#define THREAD_EXCEPTION_OFFSET 108 +#define THREAD_EXCEPTION_HANDLER 112 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/machine.cpp b/src/machine.cpp index 76953e480b..8507e9c256 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1808,13 +1808,17 @@ removeMonitor(Thread* t, object o) hash = objectHash(t, o); } - object m = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); + object p = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); - expect(t, m); + expect(t, p); if (DebugMonitors) { - fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); + fprintf(stderr, "dispose monitor %p for object %x\n", + static_cast(pointerValue(t, p)), + hash); } + + static_cast(pointerValue(t, p))->dispose(); } void @@ -2181,11 +2185,9 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): parent(parent), peer((parent ? parent->child : 0)), child(0), - waitNext(0), state(NoState), criticalLevel(0), systemThread(0), - lock(0), javaThread(javaThread), exception(0), heapIndex(0), @@ -2199,7 +2201,6 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): backupHeap(0), backupHeapIndex(0), backupHeapSizeInWords(0), - waiting(false), tracing(false) #ifdef VM_STRESS , stress(false) @@ -2254,8 +2255,6 @@ Thread::init() parent->child = this; } - expect(this, m->system->success(m->system->make(&lock))); - if (javaThread == 0) { this->javaThread = makeJavaThread(this, parent); } @@ -2283,8 +2282,6 @@ Thread::exit() void Thread::dispose() { - lock->dispose(); - if (systemThread) { systemThread->dispose(); } @@ -3422,43 +3419,49 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) t->m->finalizers = f; } -object +System::Monitor* objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); - object m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + object p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (m) { + if (p) { if (DebugMonitors) { - fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o)); + fprintf(stderr, "found monitor %p for object %x\n", + static_cast(pointerValue(t, p)), + objectHash(t, o)); } - return m; + return static_cast(pointerValue(t, p)); } else if (createNew) { PROTECT(t, o); ENTER(t, Thread::ExclusiveState); - m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (m) { + p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + if (p) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", - m, objectHash(t, o)); + static_cast(pointerValue(t, p)), + objectHash(t, o)); } - return m; + return static_cast(pointerValue(t, p)); } - object head = makeMonitorNode(t, 0, 0); - object m = makeMonitor(t, 0, 0, 0, head, head, 0); - PROTECT(t, m); + System::Monitor* m; + System::Status s = t->m->system->make(&m); + expect(t, t->m->system->success(s)); if (DebugMonitors) { - fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o)); + fprintf(stderr, "made monitor %p for object %x\n", + m, + objectHash(t, o)); } - hashMapInsert(t, t->m->monitorMap, o, m, objectHash); + p = makePointer(t, m); + hashMapInsert(t, t->m->monitorMap, o, p, objectHash); addFinalizer(t, o, removeMonitor); diff --git a/src/machine.h b/src/machine.h index 441eecc6a0..fa8d99936d 100644 --- a/src/machine.h +++ b/src/machine.h @@ -17,7 +17,6 @@ #include "finder.h" #include "processor.h" #include "constants.h" -#include "arch.h" #ifdef PLATFORM_WINDOWS # define JNICALL __stdcall @@ -1213,7 +1212,6 @@ class Machine { JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; unsigned heapPoolIndex; - unsigned recentMonitorCount; }; void @@ -1347,11 +1345,9 @@ class Thread { Thread* parent; Thread* peer; Thread* child; - Thread* waitNext; State state; unsigned criticalLevel; System::Thread* systemThread; - System::Monitor* lock; object javaThread; object exception; unsigned heapIndex; @@ -1364,7 +1360,6 @@ class Thread { uintptr_t* backupHeap; unsigned backupHeapIndex; unsigned backupHeapSizeInWords; - bool waiting; bool tracing; #ifdef VM_STRESS bool stress; @@ -2301,285 +2296,7 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); -inline bool -monitorTryAcquire(Thread* t, object monitor) -{ - if (monitorOwner(t, monitor) == t - or atomicCompareAndSwap - (reinterpret_cast(&monitorOwner(t, monitor)), 0, - reinterpret_cast(t))) - { - ++ monitorDepth(t, monitor); - return true; - } else { - return false; - } -} - -inline bool -atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, - object old, object new_) -{ - if (atomicCompareAndSwap(&cast(target, offset), - reinterpret_cast(old), - reinterpret_cast(new_))) - { - mark(t, target, offset); - return true; - } else { - return false; - } -} - -// The following two methods (monitorAtomicAppendAcquire and -// monitorAtomicPollAcquire) use the Michael and Scott Non-Blocking -// Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html - -inline void -monitorAtomicAppendAcquire(Thread* t, object monitor) -{ - PROTECT(t, monitor); - - object node = makeMonitorNode(t, t, 0); - - while (true) { - object tail = monitorAcquireTail(t, monitor); - - loadMemoryBarrier(); - - object next = monitorNodeNext(t, tail); - - loadMemoryBarrier(); - - if (tail == monitorAcquireTail(t, monitor)) { - if (next) { - atomicCompareAndSwapObject - (t, monitor, MonitorAcquireTail, tail, next); - } else if (atomicCompareAndSwapObject - (t, tail, MonitorNodeNext, 0, node)) - { - atomicCompareAndSwapObject - (t, monitor, MonitorAcquireTail, tail, node); - return; - } - } - } -} - -inline Thread* -monitorAtomicPollAcquire(Thread* t, object monitor, bool remove) -{ - while (true) { - object head = monitorAcquireHead(t, monitor); - - loadMemoryBarrier(); - - object tail = monitorAcquireTail(t, monitor); - - loadMemoryBarrier(); - - object next = monitorNodeNext(t, head); - - loadMemoryBarrier(); - - if (head == monitorAcquireHead(t, monitor)) { - if (head == tail) { - if (next) { - atomicCompareAndSwapObject - (t, monitor, MonitorAcquireTail, tail, next); - } else { - return 0; - } - } else { - Thread* value = static_cast(monitorNodeValue(t, next)); - if ((not remove) - or atomicCompareAndSwapObject - (t, monitor, MonitorAcquireHead, head, next)) - { - return value; - } - } - } - } -} - -inline void -monitorAcquire(Thread* t, object monitor) -{ - if (not monitorTryAcquire(t, monitor)) { - PROTECT(t, monitor); - - ACQUIRE(t, t->lock); - - monitorAtomicAppendAcquire(t, monitor); - - // note that we don't try to acquire the lock until we're first in - // line, both because it's fair and because we don't support - // removing elements from arbitrary positions in the queue - - while (not (t == monitorAtomicPollAcquire(t, monitor, false) - and atomicCompareAndSwap - (reinterpret_cast(&monitorOwner(t, monitor)), 0, - reinterpret_cast(t)))) - { - ENTER(t, Thread::IdleState); - - t->lock->wait(t->systemThread, 0); - } - - expect(t, t == monitorAtomicPollAcquire(t, monitor, true)); - - ++ monitorDepth(t, monitor); - } -} - -inline void -monitorRelease(Thread* t, object monitor) -{ - expect(t, monitorOwner(t, monitor) == t); - - if (-- monitorDepth(t, monitor) == 0) { - monitorOwner(t, monitor) = 0; - - storeLoadMemoryBarrier(); - - Thread* next = monitorAtomicPollAcquire(t, monitor, false); - - if (next) { - ACQUIRE(t, next->lock); - - next->lock->notify(t->systemThread); - } - } -} - -inline void -monitorAppendWait(Thread* t, object monitor) -{ - expect(t, not t->waiting); - expect(t, t->waitNext == 0); - - t->waiting = true; - - if (monitorWaitTail(t, monitor)) { - static_cast(monitorWaitTail(t, monitor))->waitNext = t; - } else { - monitorWaitHead(t, monitor) = t; - } - - monitorWaitTail(t, monitor) = t; -} - -inline void -monitorRemoveWait(Thread* t, object monitor) -{ - Thread* previous = 0; - for (Thread* current = static_cast(monitorWaitHead(t, monitor)); - current;) - { - if (t == current) { - if (current == monitorWaitHead(t, monitor)) { - monitorWaitHead(t, monitor) = t->waitNext; - } else { - previous->waitNext = t->waitNext; - } - - if (current == monitorWaitTail(t, monitor)) { - monitorWaitTail(t, monitor) = previous; - } - - t->waitNext = 0; - t->waiting = false; - - return; - } else { - previous = current; - current = current->waitNext; - } - } - - abort(t); -} - -inline bool -monitorWait(Thread* t, object monitor, int64_t time) -{ - expect(t, monitorOwner(t, monitor) == t); - - bool interrupted; - unsigned depth; - - PROTECT(t, monitor); - - { ACQUIRE(t, t->lock); - - monitorAppendWait(t, monitor); - - depth = monitorDepth(t, monitor); - monitorDepth(t, monitor) = 1; - - monitorRelease(t, monitor); - - ENTER(t, Thread::IdleState); - - interrupted = t->lock->wait(t->systemThread, time); - } - - monitorAcquire(t, monitor); - - if (t->waiting) { - monitorRemoveWait(t, monitor); - } - - monitorOwner(t, monitor) = t; - monitorDepth(t, monitor) = depth; - - return interrupted; -} - -inline Thread* -monitorPollWait(Thread* t, object monitor) -{ - Thread* next = static_cast(monitorWaitHead(t, monitor)); - - if (next) { - monitorWaitHead(t, monitor) = next->waitNext; - next->waitNext = 0; - if (next == monitorWaitTail(t, monitor)) { - monitorWaitTail(t, monitor) = 0; - } - } - - return next; -} - -inline bool -monitorNotify(Thread* t, object monitor) -{ - expect(t, monitorOwner(t, monitor) == t); - - Thread* next = monitorPollWait(t, monitor); - - if (next) { - ACQUIRE_RAW(t, next->lock); - - next->waiting = false; - - next->lock->notify(t->systemThread); - - return true; - } else { - return false; - } -} - -inline void -monitorNotifyAll(Thread* t, object monitor) -{ - while (monitorNotify(t, monitor)) { } -} - -object +System::Monitor* objectMonitor(Thread* t, object o, bool createNew); inline void @@ -2590,14 +2307,14 @@ acquire(Thread* t, object o) hash = objectHash(t, o); } - object m = objectMonitor(t, o, true); + System::Monitor* m = objectMonitor(t, o, true); if (DebugMonitors) { fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } - monitorAcquire(t, m); + acquire(t, m); } inline void @@ -2608,14 +2325,14 @@ release(Thread* t, object o) hash = objectHash(t, o); } - object m = objectMonitor(t, o, false); + System::Monitor* m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } - monitorRelease(t, m); + release(t, m); } inline void @@ -2626,19 +2343,17 @@ wait(Thread* t, object o, int64_t milliseconds) hash = objectHash(t, o); } - object m = objectMonitor(t, o, false); + System::Monitor* m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p waits %d millis on %p for %x\n", t, static_cast(milliseconds), m, hash); } - if (m and monitorOwner(t, m) == t) { - PROTECT(t, m); - + if (m and m->owner() == t->systemThread) { bool interrupted; { ENTER(t, Thread::IdleState); - interrupted = monitorWait(t, m, milliseconds); + interrupted = m->wait(t->systemThread, milliseconds); } if (interrupted) { @@ -2664,15 +2379,15 @@ notify(Thread* t, object o) hash = objectHash(t, o); } - object m = objectMonitor(t, o, false); + System::Monitor* m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies on %p for %x\n", t, m, hash); } - if (m and monitorOwner(t, m) == t) { - monitorNotify(t, m); + if (m and m->owner() == t->systemThread) { + m->notify(t->systemThread); } else { t->exception = makeIllegalMonitorStateException(t); } @@ -2681,15 +2396,15 @@ notify(Thread* t, object o) inline void notifyAll(Thread* t, object o) { - object m = objectMonitor(t, o, false); + System::Monitor* m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies all on %p for %x\n", t, m, objectHash(t, o)); } - if (m and monitorOwner(t, m) == t) { - monitorNotifyAll(t, m); + if (m and m->owner() == t->systemThread) { + m->notifyAll(t->systemThread); } else { t->exception = makeIllegalMonitorStateException(t); } diff --git a/src/types.def b/src/types.def index 184df800a0..9a704c3b91 100644 --- a/src/types.def +++ b/src/types.def @@ -111,18 +111,6 @@ (object first) (object second)) -(type monitor - (void* owner) - (void* waitHead) - (void* waitTail) - (object acquireHead) - (object acquireTail) - (unsigned depth)) - -(type monitorNode - (void* value) - (object next)) - (type continuationContext (object next) (object before) From 9d5e0bb154ab9e3c494cbc31bdea20ec3fc4adf5 Mon Sep 17 00:00:00 2001 From: Matt Klich Date: Thu, 4 Feb 2010 11:15:16 -0700 Subject: [PATCH 11/18] Updated to always specify bitness of target. cc and cxx will always have -m32 or -m64 appended based on the arch that is being built. --- makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 3a34205e8c..e94af11502 100644 --- a/makefile +++ b/makefile @@ -77,8 +77,14 @@ input = List build-cxx = g++ build-cc = gcc -cxx = $(build-cxx) -cc = $(build-cc) +ifeq ($(arch),i386) + cxx = $(build-cxx) -m32 + cc = $(build-cc) -m32 +endif +ifeq ($(arch),x86_64) + cxx = $(build-cxx) -m64 + cc = $(build-cc) -m64 +endif ar = ar ranlib = ranlib dlltool = dlltool From c9b9db16216d2cf2468081adca084a2082f0ee05 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Feb 2010 17:56:21 -0700 Subject: [PATCH 12/18] reimplement Java object monitors (second try) See commit 8120bee4dc5f9ae2dec75a907778f1479ad398bd for the original problem description and solution. That commit and a couple of related ones had to be reverted when we found they had introduced GC-safety regressions leading to crashes. This commit restores the reverted code and fixes the regressions. --- src/compile-powerpc.S | 10 +- src/continuations-x86.S | 20 +-- src/machine.cpp | 69 ++++---- src/machine.h | 346 ++++++++++++++++++++++++++++++++++++++-- src/types.def | 12 ++ 5 files changed, 390 insertions(+), 67 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index c90f16c625..8936899b53 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,11 +24,11 @@ # define GLOBAL(x) x #endif -#define THREAD_CONTINUATION 100 -#define THREAD_EXCEPTION 36 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 -#define THREAD_EXCEPTION_OFFSET 108 -#define THREAD_EXCEPTION_HANDLER 112 +#define THREAD_CONTINUATION 112 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 116 +#define THREAD_EXCEPTION_OFFSET 120 +#define THREAD_EXCEPTION_HANDLER 124 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/continuations-x86.S b/src/continuations-x86.S index 2151659ddf..aeee640388 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 176 -#define THREAD_EXCEPTION 64 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 184 -#define THREAD_EXCEPTION_OFFSET 192 -#define THREAD_EXCEPTION_HANDLER 200 +#define THREAD_CONTINUATION 192 +#define THREAD_EXCEPTION 80 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 200 +#define THREAD_EXCEPTION_OFFSET 208 +#define THREAD_EXCEPTION_HANDLER 216 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 100 -#define THREAD_EXCEPTION 36 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 104 -#define THREAD_EXCEPTION_OFFSET 108 -#define THREAD_EXCEPTION_HANDLER 112 +#define THREAD_CONTINUATION 108 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 112 +#define THREAD_EXCEPTION_OFFSET 116 +#define THREAD_EXCEPTION_HANDLER 120 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/machine.cpp b/src/machine.cpp index 8507e9c256..44247f52cb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1808,17 +1808,13 @@ removeMonitor(Thread* t, object o) hash = objectHash(t, o); } - object p = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); - expect(t, p); + expect(t, m); if (DebugMonitors) { - fprintf(stderr, "dispose monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - hash); + fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); } - - static_cast(pointerValue(t, p))->dispose(); } void @@ -2185,9 +2181,11 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): parent(parent), peer((parent ? parent->child : 0)), child(0), + waitNext(0), state(NoState), criticalLevel(0), systemThread(0), + lock(0), javaThread(javaThread), exception(0), heapIndex(0), @@ -2201,6 +2199,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): backupHeap(0), backupHeapIndex(0), backupHeapSizeInWords(0), + waiting(false), tracing(false) #ifdef VM_STRESS , stress(false) @@ -2255,6 +2254,8 @@ Thread::init() parent->child = this; } + expect(this, m->system->success(m->system->make(&lock))); + if (javaThread == 0) { this->javaThread = makeJavaThread(this, parent); } @@ -2282,6 +2283,8 @@ Thread::exit() void Thread::dispose() { + lock->dispose(); + if (systemThread) { systemThread->dispose(); } @@ -3419,52 +3422,48 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) t->m->finalizers = f; } -System::Monitor* +object objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); - object p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (p) { + if (m) { if (DebugMonitors) { - fprintf(stderr, "found monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - objectHash(t, o)); + fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o)); } - return static_cast(pointerValue(t, p)); + return m; } else if (createNew) { PROTECT(t, o); + PROTECT(t, m); - ENTER(t, Thread::ExclusiveState); + { ENTER(t, Thread::ExclusiveState); + + m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + if (m) { + if (DebugMonitors) { + fprintf(stderr, "found monitor %p for object %x\n", + m, objectHash(t, o)); + } + + return m; + } + + object head = makeMonitorNode(t, 0, 0); + m = makeMonitor(t, 0, 0, 0, head, head, 0); - p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); - if (p) { if (DebugMonitors) { - fprintf(stderr, "found monitor %p for object %x\n", - static_cast(pointerValue(t, p)), + fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o)); } - return static_cast(pointerValue(t, p)); + hashMapInsert(t, t->m->monitorMap, o, m, objectHash); + + addFinalizer(t, o, removeMonitor); } - System::Monitor* m; - System::Status s = t->m->system->make(&m); - expect(t, t->m->system->success(s)); - - if (DebugMonitors) { - fprintf(stderr, "made monitor %p for object %x\n", - m, - objectHash(t, o)); - } - - p = makePointer(t, m); - hashMapInsert(t, t->m->monitorMap, o, p, objectHash); - - addFinalizer(t, o, removeMonitor); - return m; } else { return 0; diff --git a/src/machine.h b/src/machine.h index fa8d99936d..2ea8b94bd5 100644 --- a/src/machine.h +++ b/src/machine.h @@ -17,6 +17,7 @@ #include "finder.h" #include "processor.h" #include "constants.h" +#include "arch.h" #ifdef PLATFORM_WINDOWS # define JNICALL __stdcall @@ -1345,9 +1346,11 @@ class Thread { Thread* parent; Thread* peer; Thread* child; + Thread* waitNext; State state; unsigned criticalLevel; System::Thread* systemThread; + System::Monitor* lock; object javaThread; object exception; unsigned heapIndex; @@ -1360,6 +1363,7 @@ class Thread { uintptr_t* backupHeap; unsigned backupHeapIndex; unsigned backupHeapSizeInWords; + bool waiting; bool tracing; #ifdef VM_STRESS bool stress; @@ -2296,7 +2300,316 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); -System::Monitor* +inline bool +atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, + object old, object new_) +{ + if (atomicCompareAndSwap(&cast(target, offset), + reinterpret_cast(old), + reinterpret_cast(new_))) + { + mark(t, target, offset); + return true; + } else { + return false; + } +} + +// The following two methods (monitorAtomicAppendAcquire and +// monitorAtomicPollAcquire) use the Michael and Scott Non-Blocking +// Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html + +inline void +monitorAtomicAppendAcquire(Thread* t, object monitor) +{ + PROTECT(t, monitor); + + object node = makeMonitorNode(t, t, 0); + + while (true) { + object tail = monitorAcquireTail(t, monitor); + + loadMemoryBarrier(); + + object next = monitorNodeNext(t, tail); + + loadMemoryBarrier(); + + if (tail == monitorAcquireTail(t, monitor)) { + if (next) { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, next); + } else if (atomicCompareAndSwapObject + (t, tail, MonitorNodeNext, 0, node)) + { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, node); + return; + } + } + } +} + +inline Thread* +monitorAtomicPollAcquire(Thread* t, object monitor, bool remove) +{ + while (true) { + object head = monitorAcquireHead(t, monitor); + + loadMemoryBarrier(); + + object tail = monitorAcquireTail(t, monitor); + + loadMemoryBarrier(); + + object next = monitorNodeNext(t, head); + + loadMemoryBarrier(); + + if (head == monitorAcquireHead(t, monitor)) { + if (head == tail) { + if (next) { + atomicCompareAndSwapObject + (t, monitor, MonitorAcquireTail, tail, next); + } else { + return 0; + } + } else { + Thread* value = static_cast(monitorNodeValue(t, next)); + if ((not remove) + or atomicCompareAndSwapObject + (t, monitor, MonitorAcquireHead, head, next)) + { + return value; + } + } + } + } +} + +inline bool +monitorTryAcquire(Thread* t, object monitor) +{ + if (monitorOwner(t, monitor) == t + or (monitorAtomicPollAcquire(t, monitor, false) == 0 + and atomicCompareAndSwap + (reinterpret_cast(&monitorOwner(t, monitor)), 0, + reinterpret_cast(t)))) + { + ++ monitorDepth(t, monitor); + return true; + } else { + return false; + } +} + +inline void +monitorAcquire(Thread* t, object monitor) +{ + if (not monitorTryAcquire(t, monitor)) { + PROTECT(t, monitor); + + ACQUIRE(t, t->lock); + + monitorAtomicAppendAcquire(t, monitor); + + // note that we don't try to acquire the lock until we're first in + // line, both because it's fair and because we don't support + // removing elements from arbitrary positions in the queue + + while (not (t == monitorAtomicPollAcquire(t, monitor, false) + and atomicCompareAndSwap + (reinterpret_cast(&monitorOwner(t, monitor)), 0, + reinterpret_cast(t)))) + { + ENTER(t, Thread::IdleState); + + t->lock->wait(t->systemThread, 0); + } + + expect(t, t == monitorAtomicPollAcquire(t, monitor, true)); + + ++ monitorDepth(t, monitor); + } + + assert(t, monitorOwner(t, monitor) == t); +} + +inline void +monitorRelease(Thread* t, object monitor) +{ + expect(t, monitorOwner(t, monitor) == t); + + if (-- monitorDepth(t, monitor) == 0) { + monitorOwner(t, monitor) = 0; + + storeLoadMemoryBarrier(); + + Thread* next = monitorAtomicPollAcquire(t, monitor, false); + + if (next) { + ACQUIRE(t, next->lock); + + next->lock->notify(t->systemThread); + } + } +} + +inline void +monitorAppendWait(Thread* t, object monitor) +{ + assert(t, monitorOwner(t, monitor) == t); + + expect(t, not t->waiting); + expect(t, t->waitNext == 0); + + t->waiting = true; + + if (monitorWaitTail(t, monitor)) { + static_cast(monitorWaitTail(t, monitor))->waitNext = t; + } else { + monitorWaitHead(t, monitor) = t; + } + + monitorWaitTail(t, monitor) = t; +} + +inline void +monitorRemoveWait(Thread* t, object monitor) +{ + assert(t, monitorOwner(t, monitor) == t); + + Thread* previous = 0; + for (Thread* current = static_cast(monitorWaitHead(t, monitor)); + current; current = current->waitNext) + { + if (t == current) { + if (t == monitorWaitHead(t, monitor)) { + monitorWaitHead(t, monitor) = t->waitNext; + } else { + previous->waitNext = t->waitNext; + } + + if (t == monitorWaitTail(t, monitor)) { + assert(t, t->waitNext == 0); + monitorWaitTail(t, monitor) = previous; + } + + t->waitNext = 0; + t->waiting = false; + + return; + } else { + previous = current; + } + } + + abort(t); +} + +inline bool +monitorFindWait(Thread* t, object monitor) +{ + assert(t, monitorOwner(t, monitor) == t); + + for (Thread* current = static_cast(monitorWaitHead(t, monitor)); + current; current = current->waitNext) + { + if (t == current) { + return true; + } + } + + return false; +} + +inline bool +monitorWait(Thread* t, object monitor, int64_t time) +{ + expect(t, monitorOwner(t, monitor) == t); + + bool interrupted; + unsigned depth; + + PROTECT(t, monitor); + + { ACQUIRE(t, t->lock); + + monitorAppendWait(t, monitor); + + depth = monitorDepth(t, monitor); + monitorDepth(t, monitor) = 1; + + monitorRelease(t, monitor); + + ENTER(t, Thread::IdleState); + + interrupted = t->lock->wait(t->systemThread, time); + } + + monitorAcquire(t, monitor); + + monitorDepth(t, monitor) = depth; + + if (t->waiting) { + monitorRemoveWait(t, monitor); + } else { + expect(t, not monitorFindWait(t, monitor)); + } + + assert(t, monitorOwner(t, monitor) == t); + + return interrupted; +} + +inline Thread* +monitorPollWait(Thread* t, object monitor) +{ + assert(t, monitorOwner(t, monitor) == t); + + Thread* next = static_cast(monitorWaitHead(t, monitor)); + + if (next) { + monitorWaitHead(t, monitor) = next->waitNext; + next->waiting = false; + next->waitNext = 0; + if (next == monitorWaitTail(t, monitor)) { + monitorWaitTail(t, monitor) = 0; + } + } else { + assert(t, monitorWaitTail(t, monitor) == 0); + } + + return next; +} + +inline bool +monitorNotify(Thread* t, object monitor) +{ + expect(t, monitorOwner(t, monitor) == t); + + Thread* next = monitorPollWait(t, monitor); + + if (next) { + ACQUIRE(t, next->lock); + + next->lock->notify(t->systemThread); + + return true; + } else { + return false; + } +} + +inline void +monitorNotifyAll(Thread* t, object monitor) +{ + PROTECT(t, monitor); + + while (monitorNotify(t, monitor)) { } +} + +object objectMonitor(Thread* t, object o, bool createNew); inline void @@ -2307,14 +2620,14 @@ acquire(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, true); + object m = objectMonitor(t, o, true); if (DebugMonitors) { fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } - acquire(t, m); + monitorAcquire(t, m); } inline void @@ -2325,14 +2638,14 @@ release(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } - release(t, m); + monitorRelease(t, m); } inline void @@ -2343,18 +2656,17 @@ wait(Thread* t, object o, int64_t milliseconds) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p waits %d millis on %p for %x\n", t, static_cast(milliseconds), m, hash); } - if (m and m->owner() == t->systemThread) { - bool interrupted; - { ENTER(t, Thread::IdleState); - interrupted = m->wait(t->systemThread, milliseconds); - } + if (m and monitorOwner(t, m) == t) { + PROTECT(t, m); + + bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { t->exception = makeInterruptedException(t); @@ -2379,15 +2691,15 @@ notify(Thread* t, object o) hash = objectHash(t, o); } - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies on %p for %x\n", t, m, hash); } - if (m and m->owner() == t->systemThread) { - m->notify(t->systemThread); + if (m and monitorOwner(t, m) == t) { + monitorNotify(t, m); } else { t->exception = makeIllegalMonitorStateException(t); } @@ -2396,15 +2708,15 @@ notify(Thread* t, object o) inline void notifyAll(Thread* t, object o) { - System::Monitor* m = objectMonitor(t, o, false); + object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies all on %p for %x\n", t, m, objectHash(t, o)); } - if (m and m->owner() == t->systemThread) { - m->notifyAll(t->systemThread); + if (m and monitorOwner(t, m) == t) { + monitorNotifyAll(t, m); } else { t->exception = makeIllegalMonitorStateException(t); } diff --git a/src/types.def b/src/types.def index 9a704c3b91..184df800a0 100644 --- a/src/types.def +++ b/src/types.def @@ -111,6 +111,18 @@ (object first) (object second)) +(type monitor + (void* owner) + (void* waitHead) + (void* waitTail) + (object acquireHead) + (object acquireTail) + (unsigned depth)) + +(type monitorNode + (void* value) + (object next)) + (type continuationContext (object next) (object before) From 99bb7924b0db30353ba72c43753e11fd3cdb220e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Feb 2010 18:03:32 -0700 Subject: [PATCH 13/18] fix stack frame mapping code for exception handlers Previously, the stack frame mapping code (responsible for statically calculating the map of GC roots for a method's stack frame during JIT compilation) would assume that the map of GC roots on entry to an exception handler is the same as on entry to the "try" block which the handler is attached to. Technically, this is true, but the algorithm we use does not consider whether a local variable is still "live" (i.e. will be read later) when calculating the map - only whether we can expect to find a reference there via normal (non-exceptional) control flow. This can backfire if, within a "try" block, the stack location which held an object reference on entry to the block gets overwritten with a non-reference (i.e. a primitive). If an exception is later thrown from such a block, we might end up trying to treat that non-reference as a reference during GC, which will crash the VM. The ideal way to fix this is to calculate the true interval for which each value is live and use that to produce the stack frame maps. This would provide the added benefit of ensuring that the garbage collector does not visit references which, although still present on the stack, will not be used again. However, this commit uses the less invasive strategy of ANDing together the root maps at each GC point within a "try" block and using the result as the map on entry to the corresponding exception handler(s). This should give us safe, if not optimal, results. Later on, we can refine it as described above. --- src/compile.cpp | 163 +++++++++++++++++++++++++++++++++++++----------- test/GC.java | 47 ++++++++++++++ 2 files changed, 175 insertions(+), 35 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 00fa33aa15..a695bd2367 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -588,8 +588,8 @@ print(SubroutinePath* path) if (path) { fprintf(stderr, " ("); while (true) { - fprintf(stderr, "%p", reinterpret_cast - (path->call->returnAddress->value())); + fprintf(stderr, "%p", path->call->returnAddress->resolved() ? + reinterpret_cast(path->call->returnAddress->value()) : 0); path = path->stackNext; if (path) { fprintf(stderr, ", "); @@ -603,13 +603,18 @@ print(SubroutinePath* path) class SubroutineTrace { public: - SubroutineTrace(SubroutinePath* path, SubroutineTrace* next): + SubroutineTrace(SubroutinePath* path, SubroutineTrace* next, + unsigned mapSize): path(path), - next(next) - { } + next(next), + watch(false) + { + memset(map, 0, mapSize * BytesPerWord); + } SubroutinePath* path; SubroutineTrace* next; + bool watch; uintptr_t map[0]; }; @@ -619,17 +624,21 @@ class TraceElement: public TraceHandler { static const unsigned TailCall = 1 << 1; static const unsigned LongCall = 1 << 2; - TraceElement(Context* context, object target, unsigned flags, - TraceElement* next): + TraceElement(Context* context, unsigned ip, object target, unsigned flags, + TraceElement* next, unsigned mapSize): context(context), address(0), next(next), subroutineTrace(0), - subroutineTraceCount(0), target(target), + ip(ip), + subroutineTraceCount(0), argumentIndex(0), - flags(flags) - { } + flags(flags), + watch(false) + { + memset(map, 0, mapSize * BytesPerWord); + } virtual void handleTrace(Promise* address, unsigned argumentIndex) { if (this->address == 0) { @@ -642,10 +651,12 @@ class TraceElement: public TraceHandler { Promise* address; TraceElement* next; SubroutineTrace* subroutineTrace; - unsigned subroutineTraceCount; object target; + unsigned ip; + unsigned subroutineTraceCount; unsigned argumentIndex; unsigned flags; + bool watch; uintptr_t map[0]; }; @@ -1587,7 +1598,7 @@ class Frame { TraceElement* e = context->traceLog = new (context->zone.allocate(sizeof(TraceElement) + (mapSize * BytesPerWord))) - TraceElement(context, target, flags, context->traceLog); + TraceElement(context, ip, target, flags, context->traceLog, mapSize); ++ context->traceLogCount; @@ -4923,6 +4934,63 @@ printSet(uintptr_t m, unsigned limit) } } +void +calculateTryCatchRoots(Context* context, SubroutinePath* subroutinePath, + uintptr_t* roots, unsigned mapSize, unsigned start, + unsigned end) +{ + memset(roots, 0xFF, mapSize * BytesPerWord); + + if (DebugFrameMaps) { + fprintf(stderr, "calculate try/catch roots from %d to %d", start, end); + if (subroutinePath) { + fprintf(stderr, " "); + print(subroutinePath); + } + fprintf(stderr, "\n"); + } + + for (TraceElement* te = context->traceLog; te; te = te->next) { + if (te->ip >= start and te->ip < end) { + uintptr_t* traceRoots = 0; + if (subroutinePath == 0) { + traceRoots = te->map; + te->watch = true; + } else { + for (SubroutineTrace* t = te->subroutineTrace; t; t = t->next) { + if (t->path == subroutinePath) { + traceRoots = t->map; + t->watch = true; + break; + } + } + } + + if (traceRoots) { + if (DebugFrameMaps) { + fprintf(stderr, " use roots at ip %3d: ", te->ip); + printSet(*traceRoots, mapSize); + fprintf(stderr, "\n"); + } + + for (unsigned wi = 0; wi < mapSize; ++wi) { + roots[wi] &= traceRoots[wi]; + } + } else { + if (DebugFrameMaps) { + fprintf(stderr, " skip roots at ip %3d\n", te->ip); + } + } + } + } + + if (DebugFrameMaps) { + fprintf(stderr, "result roots : "); + printSet(*roots, mapSize); + fprintf(stderr, "\n"); + } +} + unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned eventIndex, SubroutinePath* subroutinePath = 0) @@ -4969,7 +5037,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, eventIndex += 2; if (DebugFrameMaps) { - fprintf(stderr, " roots at ip %3d: ", ip); + fprintf(stderr, " roots at ip %3d: ", ip); printSet(*RUNTIME_ARRAY_BODY(roots), mapSize); fprintf(stderr, "\n"); } @@ -4998,7 +5066,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, } if (DebugFrameMaps) { - fprintf(stderr, "table roots at ip %3d: ", ip); + fprintf(stderr, " table roots at ip %3d: ", ip); printSet(*tableRoots, mapSize); fprintf(stderr, "\n"); } @@ -5022,27 +5090,27 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, } break; case PushExceptionHandlerEvent: { - unsigned reference = context->eventLog.get2(eventIndex); + unsigned start = context->eventLog.get2(eventIndex); + eventIndex += 2; + unsigned end = context->eventLog.get2(eventIndex); eventIndex += 2; - if (context->subroutineTable and context->subroutineTable[reference]) { - Subroutine* s = context->subroutineTable[reference]; + if (context->subroutineTable and context->subroutineTable[start]) { + Subroutine* s = context->subroutineTable[start]; unsigned originalEventIndex = eventIndex; for (SubroutineCall* c = s->calls; c; c = c->next) { for (SubroutinePath* p = c->paths; p; p = p->listNext) { - memcpy(RUNTIME_ARRAY_BODY(roots), - p->rootTable + (reference * mapSize), - mapSize * BytesPerWord); + calculateTryCatchRoots + (context, p, RUNTIME_ARRAY_BODY(roots), mapSize, start, end); eventIndex = calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), originalEventIndex, p); } } } else { - memcpy(RUNTIME_ARRAY_BODY(roots), - context->rootTable + (reference * mapSize), - mapSize * BytesPerWord); + calculateTryCatchRoots + (context, 0, RUNTIME_ARRAY_BODY(roots), mapSize, start, end); eventIndex = calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, 0); @@ -5052,7 +5120,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, case TraceEvent: { TraceElement* te; context->eventLog.get(eventIndex, &te, BytesPerWord); if (DebugFrameMaps) { - fprintf(stderr, "trace roots at ip %3d: ", ip); + fprintf(stderr, " trace roots at ip %3d: ", ip); printSet(*RUNTIME_ARRAY_BODY(roots), mapSize); if (subroutinePath) { fprintf(stderr, " "); @@ -5060,14 +5128,18 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, } fprintf(stderr, "\n"); } - + + uintptr_t* map; + bool watch; if (subroutinePath == 0) { - memcpy(te->map, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); + map = te->map; + watch = te->watch; } else { SubroutineTrace* trace = 0; for (SubroutineTrace* t = te->subroutineTrace; t; t = t->next) { if (t->path == subroutinePath) { trace = t; + break; } } @@ -5075,12 +5147,27 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, te->subroutineTrace = trace = new (context->zone.allocate (sizeof(SubroutineTrace) + (mapSize * BytesPerWord))) - SubroutineTrace(subroutinePath, te->subroutineTrace); + SubroutineTrace(subroutinePath, te->subroutineTrace, mapSize); ++ te->subroutineTraceCount; } - memcpy(trace->map, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); + map = trace->map; + watch = trace->watch; + } + + for (unsigned wi = 0; wi < mapSize; ++wi) { + uintptr_t v = RUNTIME_ARRAY_BODY(roots)[wi]; + + if (watch and map[wi] != v) { + if (DebugFrameMaps) { + fprintf(stderr, "dirty roots due to trace watch!\n"); + } + + context->dirtyRoots = true; + } + + map[wi] = v; } eventIndex += BytesPerWord; @@ -5184,14 +5271,12 @@ copyFrameMap(int32_t* dst, uintptr_t* src, unsigned mapSizeInBits, SubroutinePath* subroutinePath) { if (DebugFrameMaps) { - fprintf(stderr, " orig roots at ip %p: ", reinterpret_cast - (p->address->value())); + fprintf(stderr, " orig roots at ip %3d: ", p->ip); printSet(src[0], ceiling(mapSizeInBits, BitsPerWord)); print(subroutinePath); fprintf(stderr, "\n"); - fprintf(stderr, "final roots at ip %p: ", reinterpret_cast - (p->address->value())); + fprintf(stderr, " final roots at ip %3d: ", p->ip); } for (unsigned j = 0; j < p->argumentIndex; ++j) { @@ -5698,8 +5783,16 @@ compile(MyThread* t, Allocator* allocator, Context* context) codeMaxStack(t, methodCode(t, context->method))); Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); + unsigned end = exceptionHandlerEnd(eh); + if (exceptionHandlerIp(eh) >= start + and exceptionHandlerIp(eh) < end) + { + end = exceptionHandlerIp(eh); + } + context->eventLog.append(PushExceptionHandlerEvent); context->eventLog.append2(start); + context->eventLog.append2(end); for (unsigned i = 1; i < codeMaxStack(t, methodCode(t, context->method)); @@ -7211,9 +7304,9 @@ class MyProcessor: public Processor { compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, resolveMethod(t, t->m->loader, - "java/beans/PropertyChangeSupport", - "firePropertyChange", - "(Ljava/beans/PropertyChangeEvent;)V")); + "com/ecovate/nat/logic/Cache", + "findInCache", + "(Ljava/lang/String;Ljava/lang/String;JZ)Lcom/ecovate/shared/xmlrpc/Resource;")); trap(); } diff --git a/test/GC.java b/test/GC.java index eb657ef786..d04c577fc8 100644 --- a/test/GC.java +++ b/test/GC.java @@ -104,6 +104,46 @@ public class GC { System.gc(); } + private static void stackMap7(boolean predicate) { + try { + if (predicate) { + Object a = null; + } else { + Object a = null; + } + + try { + int a = 42; + throw new DummyException(); + } finally { + System.gc(); + } + } catch (DummyException e) { + e.toString(); + } + } + + private static void stackMap8(boolean predicate) { + try { + Object x = new Object(); + if (predicate) { + Object a = null; + } else { + Object a = null; + } + + try { + int a = 42; + throw new DummyException(); + } finally { + System.gc(); + x.toString(); + } + } catch (DummyException e) { + e.toString(); + } + } + public static void main(String[] args) { Object[] array = new Object[1024 * 1024]; array[0] = new Object(); @@ -139,6 +179,13 @@ public class GC { stackMap6(true); stackMap6(false); + + stackMap7(true); + stackMap7(false); + + stackMap8(true); + stackMap8(false); } + private static class DummyException extends RuntimeException { } } From c2a9424f919c8c3d1c07c80af38e84b9e09014b3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Feb 2010 18:30:13 -0700 Subject: [PATCH 14/18] implement compileTimeMemoryBarrier in arch.h This has the same implementation as programOrderMemoryBarrier in x86.h, but makes it available on all architectures. --- src/arch.h | 14 ++++++++++++++ src/windows.cpp | 2 +- src/x86.h | 6 +----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/arch.h b/src/arch.h index 1dc335de6c..622e99a2fc 100644 --- a/src/arch.h +++ b/src/arch.h @@ -17,6 +17,20 @@ extern "C" void NO_RETURN vmJump(void* address, void* base, void* stack, void* thread, uintptr_t returnLow, uintptr_t returnHigh); +namespace vm { + +inline void +compileTimeMemoryBarrier() +{ +#ifdef _MSC_VER + _ReadWriteBarrier(); +#else + __asm__ __volatile__("": : :"memory"); +#endif +} + +} // namespace vm + #if (defined ARCH_x86_32) || (defined ARCH_x86_64) # include "x86.h" #elif defined ARCH_powerpc diff --git a/src/windows.cpp b/src/windows.cpp index 4ac44e4d05..b0146334b6 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -23,7 +23,7 @@ #undef max #undef min -#include "x86.h" +#include "arch.h" #include "system.h" #define ACQUIRE(s, x) MutexResource MAKE_NAME(mutexResource_) (s, x) diff --git a/src/x86.h b/src/x86.h index f5861de2d1..a3450377a7 100644 --- a/src/x86.h +++ b/src/x86.h @@ -161,11 +161,7 @@ trap() inline void programOrderMemoryBarrier() { -#ifdef _MSC_VER - _ReadWriteBarrier(); -#else - __asm__ __volatile__("": : :"memory"); -#endif + compileTimeMemoryBarrier(); } inline void From d4cae8f15e06c08b6a2c9a3f0cd2d1498735c3dd Mon Sep 17 00:00:00 2001 From: Matt Klich Date: Fri, 5 Feb 2010 16:40:48 -0700 Subject: [PATCH 15/18] Fixed darwin build. --- makefile | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/makefile b/makefile index e94af11502..27beeb62ab 100644 --- a/makefile +++ b/makefile @@ -77,14 +77,19 @@ input = List build-cxx = g++ build-cc = gcc -ifeq ($(arch),i386) - cxx = $(build-cxx) -m32 - cc = $(build-cc) -m32 -endif -ifeq ($(arch),x86_64) - cxx = $(build-cxx) -m64 - cc = $(build-cc) -m64 +cxx = $(build-cxx) +cc = $(build-cc) +ifneq ($(platform),darwin) + ifeq ($(arch),i386) + cxx = $(cxx) -m32 + cc = $(cc) -m32 + endif + ifeq ($(arch),x86_64) + cxx = $(cxx) -m64 + cc = $(cc) -m64 + endif endif + ar = ar ranlib = ranlib dlltool = dlltool From 48cc14f8edab6a117a3a603ec2bfbfffcb234a0c Mon Sep 17 00:00:00 2001 From: Hudson Build Application account Date: Fri, 5 Feb 2010 17:15:12 -0700 Subject: [PATCH 16/18] fixed linux build because darwin fix broke it --- makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/makefile b/makefile index 27beeb62ab..7685864f6b 100644 --- a/makefile +++ b/makefile @@ -77,19 +77,19 @@ input = List build-cxx = g++ build-cc = gcc -cxx = $(build-cxx) -cc = $(build-cc) +mflag = ifneq ($(platform),darwin) ifeq ($(arch),i386) - cxx = $(cxx) -m32 - cc = $(cc) -m32 + mflag = -m32 endif ifeq ($(arch),x86_64) - cxx = $(cxx) -m64 - cc = $(cc) -m64 + mflag = -m64 endif endif +cxx = $(build-cxx) $(mflag) +cc = $(build-cc) $(mflag) + ar = ar ranlib = ranlib dlltool = dlltool From fdf9c5087b93f7077fc0150db76442a701207d3a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 19 Feb 2010 16:41:27 -0700 Subject: [PATCH 17/18] register socket with exceptfds when calling select on Windows This allows us to get connection errors like WSAECONNREFUSED in non-blocking mode. --- classpath/java-nio.cpp | 57 ++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index f11e40ca0d..07e33cc353 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -77,6 +77,19 @@ errorString(JNIEnv* e, int n) #endif } +inline jbyteArray +socketErrorString(JNIEnv* e, int n) +{ +#ifdef PLATFORM_WINDOWS + const unsigned size = 64; + char buffer[size]; + snprintf(buffer, size, "wsa code: %d", n); + return charsToArray(e, buffer); +#else + return errorString(e, n); +#endif +} + inline jbyteArray errorString(JNIEnv* e) { @@ -243,6 +256,24 @@ doListen(JNIEnv* e, int s, sockaddr_in* address) } } +bool +doFinishConnect(JNIEnv* e, int socket) +{ + int error; + socklen_t size = sizeof(int); + int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&error), &size); + + if (r != 0 or size != sizeof(int)) { + throwIOException(e); + } else if (einProgress(error)) { + return false; + } else if (error != 0) { + throwIOException(e, socketErrorString(e, error)); + } + return true; +} + bool doConnect(JNIEnv* e, int s, sockaddr_in* address) { @@ -388,18 +419,7 @@ Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, jint socket) { - int error; - socklen_t size = sizeof(int); - int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, - reinterpret_cast(&error), &size); - if (r != 0 or size != sizeof(int)) { - throwIOException(e); - } else if (einProgress(error)) { - return false; - } else if (error != 0) { - throwIOException(e, errorString(e, error)); - } - return true; + return doFinishConnect(e, socket); } extern "C" JNIEXPORT jint JNICALL @@ -460,8 +480,10 @@ Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e, socklen_t size = sizeof(int); int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &size); - if (r != 0 or size != sizeof(int) or error != 0) { - throwIOException(e, errorString(e, error)); + if (r != 0 or size != sizeof(int)) { + throwIOException(e); + } else if (error != 0) { + throwIOException(e, socketErrorString(e, error)); } } @@ -660,6 +682,7 @@ Java_java_nio_channels_SocketSelector_natSelectUpdateInterestSet(JNIEnv *, if (interest & (java_nio_channels_SelectionKey_OP_WRITE | java_nio_channels_SelectionKey_OP_CONNECT)) { FD_SET(static_cast(socket), &(s->write)); + FD_SET(static_cast(socket), &(s->except)); if (max < socket) max = socket; } else { FD_CLR(static_cast(socket), &(s->write)); @@ -727,8 +750,10 @@ Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass, socklen_t size = sizeof(int); int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &size); - if (r != 0 or size != sizeof(int) or error != 0) { + if (r != 0 or size != sizeof(int)) { throwIOException(e); + } else if (error != 0) { + throwIOException(e, socketErrorString(e, error)); } s->control.setConnected(true); } @@ -780,7 +805,7 @@ Java_java_nio_channels_SocketSelector_natUpdateReadySet(JNIEnv *, jclass, } } - if (FD_ISSET(socket, &(s->write))) { + if (FD_ISSET(socket, &(s->write)) or FD_ISSET(socket, &(s->except))) { if (interest & java_nio_channels_SelectionKey_OP_WRITE) { ready |= java_nio_channels_SelectionKey_OP_WRITE; } From 3e5b2cbc7bc5f2156a29036a6186e1e8f9f21912 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 1 Mar 2010 18:24:25 -0700 Subject: [PATCH 18/18] fix miscompilation of 64-bit volatile field reads and writes on x86_32 We were generating code which clobbered the data we were putting into 64-bit volatile fields (and potentially also clobbering the target or source object in the case of non-static fields) due to misplaced synchronization code. Reordering this code ensures that both the data and the target or source survive across calls to synchronization helper functions. --- src/compile.cpp | 58 ++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index a695bd2367..89cac7125d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -3542,6 +3542,19 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object field = resolveField(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; + if ((fieldFlags(t, field) & ACC_VOLATILE) + and BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + c->call + (c->constant + (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), + frame->append(field)); + } + Compiler::Operand* table; if (instruction == getstatic) { @@ -3572,19 +3585,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } - if ((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), - frame->append(field)); - } - switch (fieldCode(t, field)) { case ByteField: case BooleanField: @@ -4553,6 +4553,22 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + c->call + (c->constant + (getThunk(t, acquireMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), frame->append(field)); + } else { + c->storeStoreBarrier(); + } + } + Compiler::Operand* value; switch (fieldCode(t, field)) { case ByteField: @@ -4584,22 +4600,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, table = frame->popObject(); } - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), - Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), frame->append(field)); - } else { - c->storeStoreBarrier(); - } - } - switch (fieldCode(t, field)) { case ByteField: case BooleanField: