From c9b9db16216d2cf2468081adca084a2082f0ee05 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Feb 2010 17:56:21 -0700 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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