diff --git a/src/compile.cpp b/src/compile.cpp index f03e5a843d..869a75a00a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2247,9 +2247,9 @@ instanceOf64(Thread* t, object class_, object o) } uint64_t -makeNewWeakReference64(Thread* t, object class_) +makeNewGeneral64(Thread* t, object class_) { - return reinterpret_cast(makeNewWeakReference(t, class_)); + return reinterpret_cast(makeNewGeneral(t, class_)); } uint64_t @@ -2318,14 +2318,6 @@ pushReturnValue(MyThread* t, Frame* frame, unsigned code, } } -bool -emptyMethod(MyThread* t, object method) -{ - return ((methodFlags(t, method) & ACC_NATIVE) == 0) - and (codeLength(t, methodCode(t, method)) == 1) - and (codeBody(t, methodCode(t, method), 0) == return_); -} - Compiler::Operand* compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, bool useThunk, unsigned rSize, Promise* addressPromise) @@ -3967,10 +3959,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object class_ = resolveClassInPool(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; - if (classVmFlags(t, class_) & WeakReferenceFlag) { + if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { frame->pushObject (c->call - (c->constant(getThunk(t, makeNewWeakReference64Thunk)), + (c->constant(getThunk(t, makeNewGeneral64Thunk)), 0, frame->trace(0, 0), BytesPerWord, diff --git a/src/machine.cpp b/src/machine.cpp index 1b4e418b54..3946e8f647 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -481,6 +481,27 @@ postCollect(Thread* t) } } +void +finalizeObject(Thread* t, object o) +{ + for (object c = objectClass(t, o); c; c = classSuper(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object m = arrayBody(t, classMethodTable(t, c), i); + + if (strcmp(reinterpret_cast("finalize"), + &byteArrayBody(t, methodName(t, m), 0)) == 0 + and strcmp(reinterpret_cast("()V"), + &byteArrayBody(t, methodSpec(t, m), 0)) == 0) + { + t->m->processor->invoke(t, m, o); + t->exception = 0; + return; + } + } + } + abort(t); +} + object makeByteArray(Thread* t, const char* format, va_list a) { @@ -1247,6 +1268,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) hashMapInsert(t, virtualMap, method, method, methodHash); } + + if (UNLIKELY(strcmp + (reinterpret_cast("finalize"), + &byteArrayBody(t, methodName(t, method), 0)) == 0 + and strcmp + (reinterpret_cast("()V"), + &byteArrayBody(t, methodSpec(t, method), 0)) == 0 + and (not emptyMethod(t, method)))) + { + classVmFlags(t, class_) |= HasFinalizerFlag; + } } else { methodOffset(t, method) = i; @@ -1401,6 +1433,8 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType) or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); + expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0); + PROTECT(t, bootstrapClass); PROTECT(t, class_); @@ -2232,6 +2266,28 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, } } +object +makeNewGeneral(Thread* t, object class_) +{ + assert(t, t->state == Thread::ActiveState); + + object instance = makeNew(t, class_); + PROTECT(t, instance); + + if (classVmFlags(t, class_) & WeakReferenceFlag) { + ACQUIRE(t, t->m->referenceLock); + + jreferenceVmNext(t, instance) = t->m->weakReferences; + t->m->weakReferences = instance; + } + + if (classVmFlags(t, class_) & HasFinalizerFlag) { + addFinalizer(t, instance, finalizeObject); + } + + return instance; +} + object makeByteArray(Thread* t, const char* format, ...) { @@ -2498,7 +2554,8 @@ parseClass(Thread* t, const uint8_t* data, unsigned size) set(t, class_, ClassSuper, sc); classVmFlags(t, class_) - |= (classVmFlags(t, sc) & (ReferenceFlag | WeakReferenceFlag)); + |= (classVmFlags(t, sc) + & (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag)); } parseInterfaceTable(t, s, class_, pool); diff --git a/src/machine.h b/src/machine.h index 6d5ed41004..bd0a582f22 100644 --- a/src/machine.h +++ b/src/machine.h @@ -76,6 +76,7 @@ const int UnknownLine = -2; // class flags (note that we must be careful not to overlap the // standard ACC_* flags): +const unsigned HasFinalMemberFlag = 1 << 13; const unsigned SingletonFlag = 1 << 14; const unsigned ContinuationFlag = 1 << 15; @@ -87,7 +88,7 @@ const unsigned InitFlag = 1 << 3; const unsigned InitErrorFlag = 1 << 4; const unsigned PrimitiveFlag = 1 << 5; const unsigned BootstrapFlag = 1 << 6; -const unsigned HasFinalMemberFlag = 1 << 7; +const unsigned HasFinalizerFlag = 1 << 7; // method vmFlags: const unsigned ClassInitFlag = 1 << 0; @@ -1821,27 +1822,16 @@ makeNew(Thread* t, object class_) return instance; } -inline object -makeNewWeakReference(Thread* t, object class_) -{ - assert(t, t->state == Thread::ActiveState); - - object instance = makeNew(t, class_); - PROTECT(t, instance); - - ACQUIRE(t, t->m->referenceLock); - - jreferenceVmNext(t, instance) = t->m->weakReferences; - t->m->weakReferences = instance; - - return instance; -} +object +makeNewGeneral(Thread* t, object class_); inline object make(Thread* t, object class_) { - if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) { - return makeNewWeakReference(t, class_); + if (UNLIKELY(classVmFlags(t, class_) + & (WeakReferenceFlag | HasFinalizerFlag))) + { + return makeNewGeneral(t, class_); } else { return makeNew(t, class_); } @@ -2082,6 +2072,14 @@ fieldSize(Thread* t, object field) object findLoadedClass(Thread* t, object spec); +inline bool +emptyMethod(Thread* t, object method) +{ + return ((methodFlags(t, method) & ACC_NATIVE) == 0) + and (codeLength(t, methodCode(t, method)) == 1) + and (codeBody(t, methodCode(t, method), 0) == return_); +} + object parseClass(Thread* t, const uint8_t* data, unsigned length); diff --git a/src/thunks.cpp b/src/thunks.cpp index cdb37c4cc6..bb1721ffe1 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -38,7 +38,7 @@ THUNK(makeMultidimensionalArray) THUNK(throw_) THUNK(checkCast) THUNK(instanceOf64) -THUNK(makeNewWeakReference64) +THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(set) THUNK(gcIfNecessary) diff --git a/test/Finalizers.java b/test/Finalizers.java new file mode 100644 index 0000000000..b7844988bf --- /dev/null +++ b/test/Finalizers.java @@ -0,0 +1,34 @@ +public class Finalizers { + private static boolean finalized = false; + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + protected void finalize() { + finalized = true; + } + + public static void main(String[] args) { + new Finalizers(); + + expect(! finalized); + + System.gc(); + + expect(finalized); + + new Finalizers2(); + + finalized = false; + + expect(! finalized); + + System.gc(); + + expect(finalized); + } + + private static class Finalizers2 extends Finalizers { } + +}