mirror of
https://github.com/corda/corda.git
synced 2025-03-17 17:45:17 +00:00
implement basic finalization support
This implementation does not conform to the Java standard in that finalize methods are called from whichever thread happens to be garbage collecting, and that thread may hold locks, whereas the standard guarantees that finalize will be run from a thread which holds no locks. Also, an object will never be finalized more than once, even if its finalize method "rescues" (i.e. makes reachable) the object such that it might become unreachable a second time and thus a candidate for finalization once more. It's not clear to me from the standard if this is OK or not. Nonwithstanding the above, this implementation is useful for "normal" finalize methods which simply release resources associated with an object.
This commit is contained in:
parent
514d0bf7e5
commit
3787985b25
@ -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<uintptr_t>(makeNewWeakReference(t, class_));
|
||||
return reinterpret_cast<uintptr_t>(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,
|
||||
|
@ -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<const int8_t*>("finalize"),
|
||||
&byteArrayBody(t, methodName(t, m), 0)) == 0
|
||||
and strcmp(reinterpret_cast<const int8_t*>("()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<const int8_t*>("finalize"),
|
||||
&byteArrayBody(t, methodName(t, method), 0)) == 0
|
||||
and strcmp
|
||||
(reinterpret_cast<const int8_t*>("()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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -38,7 +38,7 @@ THUNK(makeMultidimensionalArray)
|
||||
THUNK(throw_)
|
||||
THUNK(checkCast)
|
||||
THUNK(instanceOf64)
|
||||
THUNK(makeNewWeakReference64)
|
||||
THUNK(makeNewGeneral64)
|
||||
THUNK(makeNew64)
|
||||
THUNK(set)
|
||||
THUNK(gcIfNecessary)
|
||||
|
34
test/Finalizers.java
Normal file
34
test/Finalizers.java
Normal file
@ -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 { }
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user