fix race condition in compile function

1. Thread A calls function F, which needs to be compiled.  So it
compiles it.
 2. Thread B calls function F, sees that it's already been compiled and
so runs it.
 3. Thread B calls function G from function F, and G needs to be
compiled, but it needs to acquire the class lock first, which A owns.
 4. Thread A causes a GC, walks thread B's stack, but function F has not
yet been added to the method tree, so it thinks the stack has no frames.
 5. Thread A finally adds function F to the method tree.
 6. Thread A causes another GC and walks thread B's stack again, and
this time it finds function F in the method tree.
 7. AAAARRRRRGGGHHH!!!!!!
This commit is contained in:
Joel Dice 2008-07-11 18:11:13 -06:00
parent befdfa4e9e
commit 0b79ab4fed

View File

@ -4255,7 +4255,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
} else {
break;
}
}
}
}
void
@ -5074,42 +5074,40 @@ compile(MyThread* t, object method)
{
MyProcessor* p = processor(t);
if (methodCompiled(t, method) == p->defaultThunk) {
PROTECT(t, method);
PROTECT(t, method);
ACQUIRE(t, t->m->classLock);
ACQUIRE(t, t->m->classLock);
if (methodCompiled(t, method) == p->defaultThunk) {
initClass(t, methodClass(t, method));
if (UNLIKELY(t->exception)) return;
if (methodCompiled(t, method) == p->defaultThunk) {
initClass(t, methodClass(t, method));
if (UNLIKELY(t->exception)) return;
object compiled;
if (methodFlags(t, method) & ACC_NATIVE) {
compiled = p->nativeThunk;
} else {
Context context(t, method);
compiled = compile(t, &context);
if (UNLIKELY(t->exception)) return;
}
if (methodCompiled(t, method) == p->defaultThunk) {
object compiled;
if (methodFlags(t, method) & ACC_NATIVE) {
compiled = p->nativeThunk;
} else {
Context context(t, method);
compiled = compile(t, &context);
if (UNLIKELY(t->exception)) return;
set(t, method, MethodCompiled, compiled);
if (methodVirtual(t, method)) {
classVtable(t, methodClass(t, method), methodOffset(t, method))
= &singletonValue(t, compiled, 0);
}
if ((methodFlags(t, method) & ACC_NATIVE) == 0) {
if (DebugMethodTree) {
fprintf(stderr, "insert method at %p\n",
&singletonValue(t, methodCompiled(t, method), 0));
}
set(t, method, MethodCompiled, compiled);
if (methodVirtual(t, method)) {
classVtable(t, methodClass(t, method), methodOffset(t, method))
= &singletonValue(t, compiled, 0);
}
if ((methodFlags(t, method) & ACC_NATIVE) == 0) {
if (DebugMethodTree) {
fprintf(stderr, "insert method at %p\n",
&singletonValue(t, methodCompiled(t, method), 0));
}
methodTree(t) = treeInsert
(t, methodTree(t), method, methodTreeSentinal(t),
compareMethodBounds);
}
methodTree(t) = treeInsert
(t, methodTree(t), method, methodTreeSentinal(t),
compareMethodBounds);
}
}
}