From d0d53e2e10b70a5fa467b4446af988286c28cca4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 16 Sep 2010 19:43:27 -0600 Subject: [PATCH] fix custom-classloader-related concurrency problems and other bugs The main changes in this commit ensure that we don't hold the global class lock when doing class resolution using application-defined classloaders. Such classloaders may do their own locking (in fact, it's almost certain), making deadlock likely when mixed with VM-level locking in various orders. Other changes include a fix to avoid overflow when waiting for extremely long intervals and a GC root stack mapping bug. --- classpath/java/lang/Thread.java | 22 +-- makefile | 4 - src/builtin.cpp | 21 ++- src/classpath-avian.cpp | 3 +- src/classpath-openjdk.cpp | 33 +++- src/compile.cpp | 284 ++++++++++++++++++-------------- src/jnienv.cpp | 4 +- src/machine.cpp | 140 +++++++++------- src/machine.h | 35 ++-- src/posix.cpp | 6 +- src/types.def | 5 +- test/GC.java | 12 ++ 12 files changed, 337 insertions(+), 232 deletions(-) diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index fec432b34e..64d0eab00a 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -15,7 +15,7 @@ import java.util.WeakHashMap; public class Thread implements Runnable { private long peer; - private boolean interrupted; + private volatile boolean interrupted; private boolean daemon; private byte state; private byte priority; @@ -141,25 +141,9 @@ public class Thread implements Runnable { public static native Thread currentThread(); - private static native void interrupt(long peer); + public native void interrupt(); - public synchronized void interrupt() { - if (peer != 0) { - interrupt(peer); - } else { - interrupted = true; - } - } - - public static boolean interrupted() { - Thread t = currentThread(); - - synchronized (t) { - boolean v = t.interrupted; - t.interrupted = false; - return v; - } - } + public native boolean interrupted(); public static boolean isInterrupted() { return currentThread().interrupted; diff --git a/makefile b/makefile index 35b66a591f..1146998f08 100644 --- a/makefile +++ b/makefile @@ -340,10 +340,6 @@ vm-sources = \ vm-asm-sources = $(src)/$(asm).S ifeq ($(process),compile) - vm-depends += \ - $(src)/compiler.h \ - $(src)/vector.h - vm-sources += \ $(src)/compiler.cpp \ $(src)/$(asm).cpp diff --git a/src/builtin.cpp b/src/builtin.cpp index c1dc0f5c29..cb45cacd04 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -84,7 +84,12 @@ Avian_avian_SystemClassLoader_resourceExists if (LIKELY(name)) { RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - return getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); + + bool r = getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); + + fprintf(stderr, "resource %s exists? %d\n", n, r); + + return r; } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); @@ -144,7 +149,11 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - System::Region* r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + if (r) { jint rSize = r->length(); r->dispose(); @@ -164,8 +173,12 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - return reinterpret_cast - (t->m->appFinder->find(RUNTIME_ARRAY_BODY(p))); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + + return reinterpret_cast(r); } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 6d64767ed7..9ee25aa8cc 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -50,7 +50,7 @@ class MyClasspath : public Classpath { return vm::makeThread (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, - root(t, Machine::BootLoader), 0, 0, group); + root(t, Machine::BootLoader), 0, 0, group, 0); } virtual void @@ -70,6 +70,7 @@ class MyClasspath : public Classpath { (Thread* t, Machine::Type type, object message, object trace, object cause) { PROTECT(t, message); + PROTECT(t, trace); PROTECT(t, cause); if (trace == 0) { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 61d54d6eed..1c3a5f1bab 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -186,7 +186,7 @@ class MyClasspath : public Classpath { return vm::makeThread (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, root(t, Machine::BootLoader), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, - 0, false); + 0, 0, false); } virtual void @@ -210,6 +210,7 @@ class MyClasspath : public Classpath { (Thread* t, Machine::Type type, object message, object trace, object cause) { PROTECT(t, message); + PROTECT(t, trace); PROTECT(t, cause); if (trace == 0) { @@ -534,6 +535,23 @@ setProperty(Thread* t, object method, object properties, t->m->processor->invoke(t, method, properties, n, v); } +object +interruptLock(Thread* t, object thread) +{ + if (threadInterruptLock(t, thread) == 0) { + PROTECT(t, thread); + ACQUIRE(t, t->m->referenceLock); + + if (threadInterruptLock(t, thread) == 0) { + object head = makeMonitorNode(t, 0, 0); + object lock = makeMonitor(t, 0, 0, 0, head, head, 0); + set(t, thread, ThreadInterruptLock, lock); + } + } + + return threadInterruptLock(t, thread); +} + } // namespace local } // namespace @@ -1255,10 +1273,14 @@ JVM_Interrupt(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); + monitorAcquire(t, local::interruptLock(t, *thread)); Thread* p = reinterpret_cast(threadPeer(t, *thread)); if (p) { interrupt(t, p); + } else { + threadInterrupted(t, *thread) = true; } + monitorRelease(t, local::interruptLock(t, *thread)); } extern "C" JNIEXPORT jboolean JNICALL @@ -1266,12 +1288,12 @@ JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) { ENTER(t, Thread::ActiveState); - acquire(t, *thread); + monitorAcquire(t, local::interruptLock(t, *thread)); bool v = threadInterrupted(t, *thread); if (clear) { threadInterrupted(t, *thread) = false; } - release(t, *thread); + monitorRelease(t, local::interruptLock(t, *thread)); return v; } @@ -2414,7 +2436,10 @@ extern "C" JNIEXPORT struct hostent* JNICALL JVM_GetHostByName(char*) { abort(); } extern "C" JNIEXPORT int JNICALL -JVM_GetHostName(char*, int) { abort(); } +JVM_GetHostName(char* name, int length) +{ + return gethostname(name, length); +} extern "C" JNIEXPORT void* JNICALL JVM_RawMonitorCreate(void) diff --git a/src/compile.cpp b/src/compile.cpp index ced35ebf15..f3a0090c27 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -327,6 +327,12 @@ compiledSize(intptr_t address) return reinterpret_cast(address)[-1]; } +intptr_t +methodCompiled(Thread* t, object method) +{ + return codeCompiled(t, methodCode(t, method)); +} + intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { @@ -2619,7 +2625,7 @@ throw_(MyThread* t, object o) (t, Machine::NullPointerExceptionType); } -// printTrace(t, t->exception); + printTrace(t, t->exception); unwind(t); } @@ -2659,6 +2665,8 @@ makeNew64(Thread* t, object class_) void gcIfNecessary(MyThread* t) { + stress(t); + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } @@ -3219,6 +3227,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3311,6 +3320,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3741,6 +3751,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -4709,6 +4720,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -5006,7 +5018,7 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } } -void +object translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intptr_t start) { @@ -5043,7 +5055,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool (t, method, exceptionHandlerCatchType(oldHandler) - 1); - if (UNLIKELY(t->exception)) return; + if (UNLIKELY(t->exception)) return 0; } else { type = 0; } @@ -5051,11 +5063,13 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type); } - set(t, methodCode(t, method), CodeExceptionHandlerTable, newTable); + return newTable; + } else { + return 0; } } -void +object translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) { object oldTable = codeLineNumberTable(t, code); @@ -5075,7 +5089,9 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) lineNumberLine(newLine) = lineNumberLine(oldLine); } - set(t, code, CodeLineNumberTable, newTable); + return newTable; + } else { + return 0; } } @@ -5527,23 +5543,23 @@ compareSubroutineTracePointers(const void* va, const void* vb) object makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements, unsigned pathFootprint, - unsigned mapCount) + TraceElement** elements, unsigned elementCount, + unsigned pathFootprint, unsigned mapCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); unsigned indexOffset = sizeof(FrameMapTableHeader); unsigned mapsOffset = indexOffset - + (context->traceLogCount * sizeof(FrameMapTableIndexElement)); + + (elementCount * sizeof(FrameMapTableIndexElement)); unsigned pathsOffset = mapsOffset + (ceiling(mapCount * mapSize, 32) * 4); object table = makeByteArray(t, pathsOffset + pathFootprint); int8_t* body = &byteArrayBody(t, table, 0); - new (body) FrameMapTableHeader(context->traceLogCount); + new (body) FrameMapTableHeader(elementCount); unsigned nextTableIndex = pathsOffset; unsigned nextMapIndex = 0; - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; unsigned mapBase = nextMapIndex; @@ -5645,27 +5661,26 @@ makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, object makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements) + TraceElement** elements, unsigned elementCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); object table = makeIntArray - (t, context->traceLogCount - + ceiling(context->traceLogCount * mapSize, 32)); + (t, elementCount + ceiling(elementCount * mapSize, 32)); - assert(t, intArrayLength(t, table) == context->traceLogCount + assert(t, intArrayLength(t, table) == elementCount + simpleFrameMapTableSize(t, context->method, table)); - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; intArrayBody(t, table, i) = static_cast(p->address->value()) - reinterpret_cast(start); - assert(t, context->traceLogCount + ceiling((i + 1) * mapSize, 32) + assert(t, elementCount + ceiling((i + 1) * mapSize, 32) <= intArrayLength(t, table)); if (mapSize) { - copyFrameMap(&intArrayBody(t, table, context->traceLogCount), p->map, + copyFrameMap(&intArrayBody(t, table, elementCount), p->map, mapSize, i * mapSize, p, 0); } } @@ -5673,7 +5688,7 @@ makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, return table; } -uint8_t* +void finish(MyThread* t, Allocator* allocator, Context* context) { Compiler* c = context->compiler; @@ -5703,7 +5718,13 @@ finish(MyThread* t, Allocator* allocator, Context* context) trap(); } + // todo: this is a CPU-intensive operation, so consider doing it + // earlier before we've acquired the global class lock to improve + // parallelism (the downside being that it may end up being a waste + // of cycles if another thread compiles the same method in parallel, + // which might be mitigated by fine-grained, per-method locking): unsigned codeSize = c->compile(); + uintptr_t* code = static_cast (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); code[0] = codeSize; @@ -5744,21 +5765,20 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - translateExceptionHandlerTable + object newExceptionHandlerTable = translateExceptionHandlerTable (t, c, context->method, reinterpret_cast(start)); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; + PROTECT(t, newExceptionHandlerTable); - translateLineNumberTable(t, c, methodCode(t, context->method), - reinterpret_cast(start)); + object newLineNumberTable = translateLineNumberTable + (t, c, methodCode(t, context->method), reinterpret_cast(start)); { object code = methodCode(t, context->method); - code = makeCode(t, 0, - codeExceptionHandlerTable(t, code), - codeLineNumberTable(t, code), - codeMaxStack(t, code), - codeMaxLocals(t, code), - 0); + code = makeCode + (t, 0, newExceptionHandlerTable, newLineNumberTable, + reinterpret_cast(start), codeMaxStack(t, code), + codeMaxLocals(t, code), 0); set(t, context->method, MethodCode, code); } @@ -5771,44 +5791,46 @@ finish(MyThread* t, Allocator* allocator, Context* context) for (TraceElement* p = context->traceLog; p; p = p->next) { assert(t, index < context->traceLogCount); - SubroutineTrace* trace = p->subroutineTrace; - unsigned myMapCount = 1; - if (trace) { - for (Subroutine* s = trace->path->call->subroutine; - s; s = s->stackNext) - { - unsigned callCount = s->callCount; - myMapCount *= callCount; - if (not s->visited) { - s->visited = true; - pathFootprint += sizeof(FrameMapTablePath) - + (sizeof(int32_t) * callCount); + if (p->address) { + SubroutineTrace* trace = p->subroutineTrace; + unsigned myMapCount = 1; + if (trace) { + for (Subroutine* s = trace->path->call->subroutine; + s; s = s->stackNext) + { + unsigned callCount = s->callCount; + myMapCount *= callCount; + if (not s->visited) { + s->visited = true; + pathFootprint += sizeof(FrameMapTablePath) + + (sizeof(int32_t) * callCount); + } } } - } - mapCount += myMapCount; + mapCount += myMapCount; - RUNTIME_ARRAY_BODY(elements)[index++] = p; + RUNTIME_ARRAY_BODY(elements)[index++] = p; - if (p->target) { - insertCallNode - (t, makeCallNode - (t, p->address->value(), p->target, p->flags, 0)); + if (p->target) { + insertCallNode + (t, makeCallNode + (t, p->address->value(), p->target, p->flags, 0)); + } } } - qsort(RUNTIME_ARRAY_BODY(elements), context->traceLogCount, + qsort(RUNTIME_ARRAY_BODY(elements), index, sizeof(TraceElement*), compareTraceElementPointers); object map; if (pathFootprint) { map = makeGeneralFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements), pathFootprint, + (t, context, start, RUNTIME_ARRAY_BODY(elements), index, pathFootprint, mapCount); } else { map = makeSimpleFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements)); + (t, context, start, RUNTIME_ARRAY_BODY(elements), index); } set(t, methodCode(t, context->method), CodePool, map); @@ -5838,12 +5860,10 @@ finish(MyThread* t, Allocator* allocator, Context* context) } syncInstructionCache(start, codeSize); - - return start; } -uint8_t* -compile(MyThread* t, Allocator* allocator, Context* context) +void +compile(MyThread* t, Context* context) { Compiler* c = context->compiler; @@ -5908,7 +5928,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) Compiler::State* state = c->saveState(); compile(t, &frame, 0); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; context->dirtyRoots = false; unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); @@ -5961,7 +5981,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) } compile(t, &frame2, exceptionHandlerIp(eh), start); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; context->eventLog.append(PopContextEvent); @@ -5977,8 +5997,6 @@ compile(MyThread* t, Allocator* allocator, Context* context) context->dirtyRoots = false; calculateFrameMaps(t, context, 0, 0); } - - return finish(t, allocator, context); } void @@ -7169,7 +7187,7 @@ class SegFaultHandler: public System::SignalHandler { t->exception = root(t, Machine::NullPointerException); } -// printTrace(t, t->exception); + printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, base, stack, &continuation); @@ -7283,10 +7301,13 @@ class MyProcessor: public Processor { object class_, object code) { + if (code) { + codeCompiled(t, code) = local::defaultThunk(static_cast(t)); + } + return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code, - local::defaultThunk(static_cast(t))); + offset, 0, name, spec, addendum, class_, code); } virtual object @@ -8083,7 +8104,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); - methodCompiled(t, method) + codeCompiled(t, methodCode(t, method)) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); @@ -8597,65 +8618,86 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (UNLIKELY(t->exception)) return; } - if (methodAddress(t, method) == defaultThunk(t)) { - ACQUIRE(t, t->m->classLock); - - if (methodAddress(t, method) == defaultThunk(t)) { - assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); - - Context context(t, bootContext, method); - uint8_t* compiled = compile(t, allocator, &context); - if (UNLIKELY(t->exception)) return; - - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", compiled); - } - - // We can't set the MethodCompiled field on the original method - // before it is placed into the method tree, since another - // thread might call the method, from which stack unwinding - // would fail (since there is not yet an entry in the method - // tree). However, we can't insert the original method into the - // tree before setting the MethodCompiled field on it since we - // rely on that field to determine its position in the tree. - // Therefore, we insert a clone in its place. Later, we'll - // replace the clone with the original to save memory. - - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodAddendum(t, method), - methodClass(t, method), - methodCode(t, method), - reinterpret_cast(compiled)); - - setRoot - (t, MethodTree, treeInsert - (t, &(context.zone), root(t, MethodTree), - reinterpret_cast(compiled), clone, - root(t, MethodTreeSentinal), - compareIpToMethodBounds)); - - storeStoreMemoryBarrier(); - - methodCompiled(t, method) = reinterpret_cast(compiled); - - if (methodVirtual(t, method)) { - classVtable(t, methodClass(t, method), methodOffset(t, method)) - = compiled; - } - - treeUpdate(t, root(t, MethodTree), reinterpret_cast(compiled), - method, root(t, MethodTreeSentinal), compareIpToMethodBounds); - } + if (methodAddress(t, method) != defaultThunk(t)) { + return; } + + assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); + + // We must avoid acquiring any locks until after the first pass of + // compilation, since this pass may trigger classloading operations + // involving application classloaders and thus the potential for + // deadlock. To make this safe, we use a private clone of the + // method so that we won't be confused if another thread updates the + // original while we're working. + + object clone = makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodName(t, method), + methodSpec(t, method), + methodAddendum(t, method), + methodClass(t, method), + methodCode(t, method)); + + loadMemoryBarrier(); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + PROTECT(t, clone); + + Context context(t, bootContext, clone); + compile(t, &context); + if (UNLIKELY(t->exception)) return; + + ACQUIRE(t, t->m->classLock); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + finish(t, allocator, &context); + if (UNLIKELY(t->exception)) return; + + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", + reinterpret_cast(methodCompiled(t, clone))); + } + + // We can't update the MethodCode field on the original method + // before it is placed into the method tree, since another thread + // might call the method, from which stack unwinding would fail + // (since there is not yet an entry in the method tree). However, + // we can't insert the original method into the tree before updating + // the MethodCode field on it since we rely on that field to + // determine its position in the tree. Therefore, we insert the + // clone in its place. Later, we'll replace the clone with the + // original to save memory. + + setRoot + (t, MethodTree, treeInsert + (t, &(context.zone), root(t, MethodTree), + methodCompiled(t, clone), clone, root(t, MethodTreeSentinal), + compareIpToMethodBounds)); + + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, methodCode(t, clone)); + + if (methodVirtual(t, method)) { + classVtable(t, methodClass(t, method), methodOffset(t, method)) + = reinterpret_cast(methodCompiled(t, clone)); + } + + treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone), + method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } object& diff --git a/src/jnienv.cpp b/src/jnienv.cpp index ed36e9451d..b09c0815c8 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2007,11 +2007,11 @@ parseSize(const char* s) return 0; } else if (s[length - 1] == 'k') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024; } else if (s[length - 1] == 'm') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024; } else { return atoi(s); diff --git a/src/machine.cpp b/src/machine.cpp index 243ef6be9c..0542a5c216 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -726,6 +726,8 @@ internByteArray(Thread* t, object array) { PROTECT(t, array); + ACQUIRE(t, t->m->referenceLock); + object n = hashMapFindNode (t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual); if (n) { @@ -1199,7 +1201,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -1297,7 +1299,6 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap, methodSpec(t, method), 0, class_, - 0, 0); hashMapInsert(t, virtualMap, method, method, methodHash); @@ -1705,6 +1706,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, // todo: arrays should implement Cloneable and Serializable if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { + PROTECT(t, loader); PROTECT(t, spec); PROTECT(t, elementClass); @@ -2014,10 +2016,10 @@ boot(Thread* t) setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); m->processor->boot(t, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod - (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0); + (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" @@ -3217,59 +3219,65 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) { return resolveSystemClass(t, loader, spec, throw_); } else { + expect(t, throw_); + PROTECT(t, loader); PROTECT(t, spec); - ACQUIRE(t, t->m->classLock); + { ACQUIRE(t, t->m->classLock); - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + object class_ = hashMapFind + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + + if (class_) { + return class_; + } } - object class_ = hashMapFind - (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + object class_; + if (byteArrayBody(t, spec, 0) == '[') { + class_ = resolveArrayClass(t, loader, spec, throw_); + } else { + if (root(t, Machine::LoadClassMethod) == 0) { + object m = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", + "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - if (class_ == 0) { - if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec, throw_); - } else { - if (root(t, Machine::LoadClassMethod) == 0) { - object m = resolveMethod - (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", - "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + if (m) { + setRoot(t, Machine::LoadClassMethod, m); - if (m) { - setRoot(t, Machine::LoadClassMethod, m); - - object classLoaderClass = type(t, Machine::ClassLoaderType); + object classLoaderClass = type(t, Machine::ClassLoaderType); - if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { - resolveSystemClass - (t, root(t, Machine::BootLoader), - vm::className(t, classLoaderClass)); - } - } - } + if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, classLoaderClass)); + } + } + } + + if (LIKELY(t->exception == 0)) { + object method = findVirtualMethod + (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); if (LIKELY(t->exception == 0)) { - object method = findVirtualMethod - (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); + PROTECT(t, method); - if (LIKELY(t->exception == 0)) { - PROTECT(t, method); + RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast + (&byteArrayBody(t, spec, 0))); - RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); - replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast - (&byteArrayBody(t, spec, 0))); + object specString = makeString(t, "%s", s); - object specString = makeString(t, "%s", s); + class_ = t->m->processor->invoke(t, method, loader, specString); - class_ = t->m->processor->invoke(t, method, loader, specString); - - if (LIKELY(class_ and t->exception == 0)) { - class_ = jclassVmClass(t, class_); - } + if (LIKELY(class_ and t->exception == 0)) { + class_ = jclassVmClass(t, class_); } } } @@ -3278,6 +3286,8 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) if (class_) { PROTECT(t, class_); + ACQUIRE(t, t->m->classLock); + hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_ and t->exception == 0) { @@ -3659,8 +3669,8 @@ collect(Thread* t, Heap::CollectionType type) ENTER(t, Thread::ExclusiveState); #ifdef VM_STRESS - bool stress = t->stress; - if (not stress) t->stress = true; + bool stress = (t->flags |= Thread::StressFlag); + if (not stress) atomicOr(&(t->flags), Thread::StressFlag); #endif Machine* m = t->m; @@ -3681,7 +3691,7 @@ collect(Thread* t, Heap::CollectionType type) m->fixedFootprint = 0; #ifdef VM_STRESS - if (not stress) t->stress = false; + if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); #endif object f = t->m->finalizeQueue; @@ -4005,6 +4015,8 @@ vmPrintTrace(Thread* t) Thread* t; } v(t); + fprintf(stderr, "debug trace for thread %p\n", t); + t->m->processor->walkStack(t, &v); } @@ -4012,24 +4024,24 @@ vmPrintTrace(Thread* t) void* vmAddressFromLine(Thread* t, object m, unsigned line) { - object code = methodCode(t, m); - printf("code: %p\n", code); - object lnt = codeLineNumberTable(t, code); - printf("lnt: %p\n", lnt); + object code = methodCode(t, m); + printf("code: %p\n", code); + object lnt = codeLineNumberTable(t, code); + printf("lnt: %p\n", lnt); - if (lnt) { - unsigned last = 0; - unsigned bottom = 0; - unsigned top = lineNumberTableLength(t, lnt); - for(unsigned i = bottom; i < top; i++) - { - LineNumber* ln = lineNumberTableBody(t, lnt, i); - if(lineNumberLine(ln) == line) - return reinterpret_cast(lineNumberIp(ln)); - else if(lineNumberLine(ln) > line) - return reinterpret_cast(last); - last = lineNumberIp(ln); - } - } - return 0; + if (lnt) { + unsigned last = 0; + unsigned bottom = 0; + unsigned top = lineNumberTableLength(t, lnt); + for(unsigned i = bottom; i < top; i++) + { + LineNumber* ln = lineNumberTableBody(t, lnt, i); + if(lineNumberLine(ln) == line) + return reinterpret_cast(lineNumberIp(ln)); + else if(lineNumberLine(ln) > line) + return reinterpret_cast(last); + last = lineNumberIp(ln); + } + } + return 0; } diff --git a/src/machine.h b/src/machine.h index ec2677109e..b7b154ffa2 100644 --- a/src/machine.h +++ b/src/machine.h @@ -30,6 +30,9 @@ #define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x) +#define ACQUIRE_OBJECT(t, x) \ + ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) + #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) @@ -1507,20 +1510,19 @@ shutDown(Thread* t); inline void stress(Thread* t) { - if ((not t->stress) - and (not t->tracing) + if ((t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and t->state != Thread::NoState and t->state != Thread::IdleState) { - t->stress = true; + atomicOr(&(t->flags), Thread::StressFlag); # ifdef VM_STRESS_MAJOR - collect(t, Heap::MajorCollection); + collect(t, Heap::MajorCollection); # else // not VM_STRESS_MAJOR - collect(t, Heap::MinorCollection); + collect(t, Heap::MinorCollection); # endif // not VM_STRESS_MAJOR - t->stress = false; + atomicAnd(&(t->flags), ~Thread::StressFlag); } } @@ -2607,6 +2609,21 @@ monitorNotifyAll(Thread* t, object monitor) while (monitorNotify(t, monitor)) { } } +class ObjectMonitorResource { + public: + ObjectMonitorResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + monitorAcquire(protector.t, o); + } + + ~ObjectMonitorResource() { + monitorRelease(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + object objectMonitor(Thread* t, object o, bool createNew); @@ -2621,8 +2638,7 @@ acquire(Thread* t, object o) object m = objectMonitor(t, o, true); if (DebugMonitors) { - fprintf(stderr, "thread %p acquires %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } monitorAcquire(t, m); @@ -2639,8 +2655,7 @@ release(Thread* t, object o) object m = objectMonitor(t, o, false); if (DebugMonitors) { - fprintf(stderr, "thread %p releases %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } monitorRelease(t, m); diff --git a/src/posix.cpp b/src/posix.cpp index a40d555334..0a96f70f29 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,6 +14,8 @@ # define _XOPEN_SOURCE #endif +#define __STDC_CONSTANT_MACROS + #include "sys/mman.h" #include "sys/types.h" #include "sys/stat.h" @@ -287,7 +289,9 @@ class MySystem: public System { owner_ = 0; pthread_mutex_unlock(&mutex); - if (time) { + // pretend anything greater than one million years (in + // milliseconds) is infinity so as to avoid overflow: + if (time and time < INT64_C(31536000000000000)) { int64_t then = s->now() + time; timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 }; int rv UNUSED = pthread_cond_timedwait diff --git a/src/types.def b/src/types.def index 0ddeb92a3c..854798c84e 100644 --- a/src/types.def +++ b/src/types.def @@ -26,8 +26,7 @@ (type field avian/VMField) -(type method avian/VMMethod - (intptr_t compiled)) +(type method avian/VMMethod) (type addendum avian/Addendum) @@ -64,6 +63,7 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) + (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) @@ -163,6 +163,7 @@ (type thread java/lang/Thread (require object sleepLock) + (require object interruptLock) (require uint8_t interrupted) (alias peer uint64_t eetop)) diff --git a/test/GC.java b/test/GC.java index d04c577fc8..9fabee0cc9 100644 --- a/test/GC.java +++ b/test/GC.java @@ -1,4 +1,14 @@ public class GC { + private static final Integer cache[] = new Integer[100]; + private static final Integer MAX_INT_OBJ = new Integer(Integer.MAX_VALUE); + + private static Integer valueOf(int i) { + try { + return cache[i]; + } catch (ArrayIndexOutOfBoundsException e) { + return (i == Integer.MAX_VALUE) ? MAX_INT_OBJ : new Integer(i); + } + } private static void small() { for (int i = 0; i < 1024; ++i) { @@ -145,6 +155,8 @@ public class GC { } public static void main(String[] args) { + valueOf(1000); + Object[] array = new Object[1024 * 1024]; array[0] = new Object();