diff --git a/src/compile.cpp b/src/compile.cpp index 4d7d7cecdd..25fa2c5ab5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2011,7 +2011,7 @@ findExceptionHandler(Thread* t, object method, void* ip) if (key >= start and key < end) { object catchType = arrayBody(t, table, i + 1); - if (catchType == 0 or instanceOf(t, catchType, t->exception)) { + if (exceptionMatch(t, catchType, t->exception)) { return compiled + intArrayBody(t, index, (i * 3) + 2); } } @@ -8249,7 +8249,7 @@ class SignalHandler: public System::SignalHandler { t->exception = vm::root(t, root); } - //printTrace(t, t->exception); + // printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, frame, stack, &continuation); @@ -9237,6 +9237,52 @@ fixupHeap(MyThread* t UNUSED, uintptr_t* map, unsigned size, uintptr_t* heap) } } +void +resetClassRuntimeState(Thread* t, object c, uintptr_t* heap, unsigned heapSize) +{ + classRuntimeDataIndex(t, c) = 0; + + if (classArrayElementSize(t, c) == 0) { + object staticTable = classStaticTable(t, c); + if (staticTable) { + for (unsigned i = 0; i < singletonCount(t, staticTable); ++i) { + if (singletonIsObject(t, staticTable, i) + and (reinterpret_cast + (singletonObject(t, staticTable, i)) < heap or + reinterpret_cast + (singletonObject(t, staticTable, i)) > heap + heapSize)) + { + singletonObject(t, staticTable, i) = 0; + } + } + } + } + + if (classMethodTable(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object m = arrayBody(t, classMethodTable(t, c), i); + + methodNativeID(t, m) = 0; + methodRuntimeDataIndex(t, m) = 0; + + if (methodVmFlags(t, m) & ClassInitFlag) { + classVmFlags(t, c) |= NeedInitFlag; + classVmFlags(t, c) &= ~InitErrorFlag; + } + } + } + + t->m->processor->initVtable(t, c); +} + +void +resetRuntimeState(Thread* t, object map, uintptr_t* heap, unsigned heapSize) +{ + for (HashMapIterator it(t, map); it.hasMore();) { + resetClassRuntimeState(t, tripleSecond(t, it.next()), heap, heapSize); + } +} + void fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code) { @@ -9339,7 +9385,11 @@ boot(MyThread* t, BootImage* image, uint8_t* code) // fprintf(stderr, "code from %p to %p\n", // code, code + image->codeSize); - fixupHeap(t, heapMap, heapMapSizeInWords, heap); + static bool fixed = false; + + if (not fixed) { + fixupHeap(t, heapMap, heapMapSizeInWords, heap); + } t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); @@ -9384,11 +9434,30 @@ boot(MyThread* t, BootImage* image, uint8_t* code) findThunks(t, image, code); - fixupVirtualThunks(t, code); + if (fixed) { + resetRuntimeState + (t, classLoaderMap(t, root(t, Machine::BootLoader)), heap, + image->heapSize); - fixupMethods - (t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code); - fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); + resetRuntimeState + (t, classLoaderMap(t, root(t, Machine::AppLoader)), heap, + image->heapSize); + + for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) { + resetClassRuntimeState + (t, type(t, static_cast(i)), heap, image->heapSize); + } + } else { + fixupVirtualThunks(t, code); + + fixupMethods + (t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code); + + fixupMethods + (t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); + } + + fixed = true; setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); } diff --git a/src/heap.cpp b/src/heap.cpp index e441640364..b9f20f82d8 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -848,13 +848,20 @@ bitset(Context* c UNUSED, void* o) void free(Context* c, Fixie** fixies) { - for (Fixie** p = fixies; *p;) { - Fixie* f = *p; + for (Fixie* p = *fixies; p;) { + Fixie* f = p; + p = f->next; if (f->immortal()) { - p = &(f->next); + if (DebugFixies) { + fprintf(stderr, "reset immortal fixie %p\n", f); + } + memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask)); + f->next = 0; + f->handle = 0; + f->marked = false; + f->dirty = false; } else { - *p = f->next; if (DebugFixies) { fprintf(stderr, "free fixie %p\n", f); } diff --git a/src/interpret.cpp b/src/interpret.cpp index 65293463f0..6e04cd4942 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -698,7 +698,7 @@ findExceptionHandler(Thread* t, object method, unsigned ip) } } - if (catchType == 0 or instanceOf(t, catchType, t->exception)) { + if (exceptionMatch(t, catchType, t->exception)) { return eh; } } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 4d4518febd..34f82efc65 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3024,6 +3024,8 @@ boot(Thread* t, uintptr_t*) setRoot(t, Machine::OutOfMemoryError, makeThrowable(t, Machine::OutOfMemoryErrorType)); + setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType)); + setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t)); threadDaemon(t, root(t, Machine::FinalizerThread)) = true; diff --git a/src/machine.cpp b/src/machine.cpp index bdfdef42a3..6f918e7ca6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -138,35 +138,37 @@ dispose(Thread* t, Thread* o, bool remove) } void -joinAll(Thread* m, Thread* o) +visitAll(Thread* m, Thread* o, void (*visit)(Thread*, Thread*)) { for (Thread* p = o->child; p;) { Thread* child = p; p = p->peer; - joinAll(m, child); + visitAll(m, child, visit); } - join(m, o); + visit(m, o); } void -disposeAll(Thread* m, Thread* o) +disposeNoRemove(Thread* m, Thread* o) { - for (Thread* p = o->child; p;) { - Thread* child = p; - p = p->peer; - disposeAll(m, child); - } - dispose(m, o, false); } +void +interruptDaemon(Thread* m, Thread* o) +{ + if (o->flags & Thread::DaemonFlag) { + interrupt(m, o); + } +} + void turnOffTheLights(Thread* t) { expect(t, t->m->liveCount == 1); - joinAll(t, t->m->rootThread); + visitAll(t, t->m->rootThread, join); enter(t, Thread::ExitState); @@ -215,7 +217,7 @@ turnOffTheLights(Thread* t) Machine* m = t->m; - disposeAll(t, t->m->rootThread); + visitAll(t, t->m->rootThread, disposeNoRemove); System* s = m->system; Heap* h = m->heap; @@ -2443,6 +2445,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, collecting(false), triedBuiltinOnLoad(false), dumpedHeapOnOOM(false), + alive(true), heapPoolIndex(0) { heap->setClient(heapClient); @@ -2694,6 +2697,17 @@ shutDown(Thread* t) } } } + + // interrupt daemon threads and tell them to die + + // todo: be more aggressive about killing daemon threads, e.g. at + // any GC point, not just at waits/sleeps + { ACQUIRE(t, t->m->stateLock); + + t->m->alive = false; + + visitAll(t, t->m->rootThread, interruptDaemon); + } } void @@ -3247,9 +3261,7 @@ classInitializer(Thread* t, object class_) { object o = arrayBody(t, classMethodTable(t, class_), i); - if (vm::strcmp(reinterpret_cast(""), - &byteArrayBody(t, methodName(t, o), 0)) == 0) - { + if (methodVmFlags(t, o) & ClassInitFlag) { return o; } } diff --git a/src/machine.h b/src/machine.h index 70f3d7295e..b11ca98667 100644 --- a/src/machine.h +++ b/src/machine.h @@ -157,8 +157,7 @@ const unsigned ContinuationFlag = 1 << 11; // method vmFlags: const unsigned ClassInitFlag = 1 << 0; -const unsigned CompiledFlag = 1 << 1; -const unsigned ConstructorFlag = 1 << 2; +const unsigned ConstructorFlag = 1 << 1; #ifndef JNI_VERSION_1_6 #define JNI_VERSION_1_6 0x00010006 @@ -1266,6 +1265,7 @@ class Machine { ArithmeticException, ArrayIndexOutOfBoundsException, OutOfMemoryError, + Shutdown, VirtualFileFinders, VirtualFiles }; @@ -1322,6 +1322,7 @@ class Machine { bool collecting; bool triedBuiltinOnLoad; bool dumpedHeapOnOOM; + bool alive; JavaVMVTable javaVMVTable; JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; @@ -1357,6 +1358,9 @@ run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), void checkDaemon(Thread* t); +object& +root(Thread* t, Machine::Root root); + extern "C" uint64_t vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments, void* checkpoint); @@ -1507,7 +1511,7 @@ class Thread { vm::run(t, runThread, 0); - if (t->exception) { + if (t->exception and t->exception != root(t, Machine::Shutdown)) { printTrace(t, t->exception); } @@ -3182,7 +3186,11 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - throwNew(t, Machine::InterruptedExceptionType); + if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) { + throwNew(t, Machine::InterruptedExceptionType); + } else { + throw_(t, root(t, Machine::Shutdown)); + } } } else { throwNew(t, Machine::IllegalMonitorStateExceptionType); @@ -3256,6 +3264,14 @@ getAndClearInterrupted(Thread* t, Thread* target) } } +inline bool +exceptionMatch(Thread* t, object type, object exception) +{ + return type == 0 + or (exception != root(t, Machine::Shutdown) + and instanceOf(t, type, t->exception)); +} + object intern(Thread* t, object s);