From fca98df55bcce62c5c6d70e246acb48ab0f64be6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 4 Aug 2010 18:27:54 -0600 Subject: [PATCH] fix process=interpret class initialization regression A long time ago, I refactored the class initialization code in the VM, but did not notice until today that it had caused the process=interpret build to break on certain recursive initializations. In particular, we were not always detecting when a thread recursively tried to initialize a class it was already in the process of initializing, leading to the mistaken assumption that another thread was initializing it and that we should wait until it was done, in which case we would wait forever. This commit ensures that we always detect recursive initialization and short-circuit it. --- src/compile.cpp | 11 +++++++++++ src/interpret.cpp | 26 ++++++++++++++++++++------ src/machine.cpp | 12 +++++------- src/processor.h | 3 +++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index b84d2ae6e8..e5d7a7df2d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7332,6 +7332,17 @@ class MyProcessor: public Processor { } } + virtual bool + isInitializing(Thread* t, object c) + { + for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { + if (s->class_ == c) { + return true; + } + } + return false; + } + virtual void visitObjects(Thread* vmt, Heap::Visitor* v) { diff --git a/src/interpret.cpp b/src/interpret.cpp index 3ca09f7780..e63613cb54 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -761,12 +761,6 @@ invokeNative(Thread* t, object method) bool classInit2(Thread* t, object class_, unsigned ipOffset) { - for (ClassInitList* list = t->classInitList; list; list = list->next) { - if (list->class_ == class_) { - return false; - } - } - PROTECT(t, class_); if (preInitClass(t, class_)) { @@ -3111,6 +3105,26 @@ class MyProcessor: public Processor { // ignore } + virtual bool + isInitializing(vm::Thread* vmt, object c) + { + Thread* t = static_cast(vmt); + + for (ClassInitList* list = t->classInitList; list; list = list->next) { + if (list->class_ == c) { + return true; + } + } + + for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { + if (s->class_ == c) { + return true; + } + } + + return false; + } + virtual void visitObjects(vm::Thread* vmt, Heap::Visitor* v) { diff --git a/src/machine.cpp b/src/machine.cpp index 44230b0fd2..01b766de93 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3309,13 +3309,11 @@ preInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (classVmFlags(t, c) & NeedInitFlag) { if (classVmFlags(t, c) & InitFlag) { - // the class is currently being initialized. If this the - // thread which is initializing it, we should not try to - // initialize it recursively. - for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { - if (s->class_ == c) { - return false; - } + // If the class is currently being initialized and this the thread + // which is initializing it, we should not try to initialize it + // recursively. + if (t->m->processor->isInitializing(t, c)) { + return false; } // some other thread is on the job - wait for it to finish. diff --git a/src/processor.h b/src/processor.h index 4e7b54f072..398b2d930b 100644 --- a/src/processor.h +++ b/src/processor.h @@ -81,6 +81,9 @@ class Processor { virtual void initVtable(Thread* t, object c) = 0; + virtual bool + isInitializing(Thread* t, object c) = 0; + virtual void visitObjects(Thread* t, Heap::Visitor* v) = 0;