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.
This commit is contained in:
Joel Dice 2010-09-16 19:43:27 -06:00
parent f485016637
commit d0d53e2e10
12 changed files with 337 additions and 232 deletions

View File

@ -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;

View File

@ -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

View File

@ -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<int64_t>
(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<int64_t>(r);
} else {
t->exception = t->m->classpath->makeThrowable
(t, Machine::NullPointerExceptionType);

View File

@ -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) {

View File

@ -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<Thread*>(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)

View File

@ -327,6 +327,12 @@ compiledSize(intptr_t address)
return reinterpret_cast<uintptr_t*>(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<intptr_t>(p->address->value())
- reinterpret_cast<intptr_t>(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<uintptr_t*>
(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<intptr_t>(start));
if (UNLIKELY(t->exception)) return 0;
if (UNLIKELY(t->exception)) return;
PROTECT(t, newExceptionHandlerTable);
translateLineNumberTable(t, c, methodCode(t, context->method),
reinterpret_cast<intptr_t>(start));
object newLineNumberTable = translateLineNumberTable
(t, c, methodCode(t, context->method), reinterpret_cast<intptr_t>(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<uintptr_t>(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<MyThread*>(t));
}
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, 0, name, spec, addendum, class_, code,
local::defaultThunk(static_cast<MyThread*>(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<uintptr_t>(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<intptr_t>(compiled));
setRoot
(t, MethodTree, treeInsert
(t, &(context.zone), root(t, MethodTree),
reinterpret_cast<intptr_t>(compiled), clone,
root(t, MethodTreeSentinal),
compareIpToMethodBounds));
storeStoreMemoryBarrier();
methodCompiled(t, method) = reinterpret_cast<intptr_t>(compiled);
if (methodVirtual(t, method)) {
classVtable(t, methodClass(t, method), methodOffset(t, method))
= compiled;
}
treeUpdate(t, root(t, MethodTree), reinterpret_cast<intptr_t>(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<void*>(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<void*>(methodCompiled(t, clone));
}
treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone),
method, root(t, MethodTreeSentinal), compareIpToMethodBounds);
}
object&

View File

@ -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);

View File

@ -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<char*>
(&byteArrayBody(t, spec, 0)));
RUNTIME_ARRAY(char, s, byteArrayLength(t, spec));
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
(&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<void*>(lineNumberIp(ln));
else if(lineNumberLine(ln) > line)
return reinterpret_cast<void*>(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<void*>(lineNumberIp(ln));
else if(lineNumberLine(ln) > line)
return reinterpret_cast<void*>(last);
last = lineNumberIp(ln);
}
}
return 0;
}

View File

@ -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);

View File

@ -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

View File

@ -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))

View File

@ -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();