re PR libgcj/10596 (Reference and String.intern don't work together)
PR libgcj/10596: * include/jvm.h (_Jv_FinalizeString, _Jv_RegisterStringFinalizer): Declare. * java/lang/natString.cc (_Jv_FinalizeString): Renamed from unintern. (intern): Updated. (_Jv_NewStringUtf8Const): Likewise. * java/lang/ref/natReference.cc (finalize_referred_to_object): Add special case when finalizing a String. (in_hash): New function. (_Jv_RegisterStringFinalizer): Likewise. (maybe_add_finalize): Likewise. From-SVN: r71915
This commit is contained in:
parent
51ac684e52
commit
2cd5614273
|
@ -1,3 +1,18 @@
|
||||||
|
2003-09-29 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
|
PR libgcj/10596:
|
||||||
|
* include/jvm.h (_Jv_FinalizeString,
|
||||||
|
_Jv_RegisterStringFinalizer): Declare.
|
||||||
|
* java/lang/natString.cc (_Jv_FinalizeString): Renamed from
|
||||||
|
unintern.
|
||||||
|
(intern): Updated.
|
||||||
|
(_Jv_NewStringUtf8Const): Likewise.
|
||||||
|
* java/lang/ref/natReference.cc (finalize_referred_to_object):
|
||||||
|
Add special case when finalizing a String.
|
||||||
|
(in_hash): New function.
|
||||||
|
(_Jv_RegisterStringFinalizer): Likewise.
|
||||||
|
(maybe_add_finalize): Likewise.
|
||||||
|
|
||||||
2003-09-29 Michael Koch <konqueror@gmx.de>
|
2003-09-29 Michael Koch <konqueror@gmx.de>
|
||||||
|
|
||||||
* java/net/InetAddress.java:
|
* java/net/InetAddress.java:
|
||||||
|
|
|
@ -290,6 +290,12 @@ void _Jv_GCRegisterDisappearingLink (jobject *objp);
|
||||||
implement soft references. */
|
implement soft references. */
|
||||||
jboolean _Jv_GCCanReclaimSoftReference (jobject obj);
|
jboolean _Jv_GCCanReclaimSoftReference (jobject obj);
|
||||||
|
|
||||||
|
/* Register a finalizer for a String object. This is only used by
|
||||||
|
the intern() implementation. */
|
||||||
|
void _Jv_RegisterStringFinalizer (jobject str);
|
||||||
|
/* This is called to actually finalize a possibly-intern()d String. */
|
||||||
|
void _Jv_FinalizeString (jobject str);
|
||||||
|
|
||||||
/* Return approximation of total size of heap. */
|
/* Return approximation of total size of heap. */
|
||||||
long _Jv_GCTotalMemory (void);
|
long _Jv_GCTotalMemory (void);
|
||||||
/* Return approximation of total free memory. */
|
/* Return approximation of total free memory. */
|
||||||
|
|
|
@ -31,7 +31,6 @@ details. */
|
||||||
#include <gnu/gcj/runtime/StringBuffer.h>
|
#include <gnu/gcj/runtime/StringBuffer.h>
|
||||||
#include <jvm.h>
|
#include <jvm.h>
|
||||||
|
|
||||||
static void unintern (jobject);
|
|
||||||
static jstring* strhash = NULL;
|
static jstring* strhash = NULL;
|
||||||
static int strhash_count = 0; /* Number of slots used in strhash. */
|
static int strhash_count = 0; /* Number of slots used in strhash. */
|
||||||
static int strhash_size = 0; /* Number of slots available in strhash.
|
static int strhash_size = 0; /* Number of slots available in strhash.
|
||||||
|
@ -173,28 +172,38 @@ java::lang::String::intern()
|
||||||
jstring* ptr = _Jv_StringGetSlot(this);
|
jstring* ptr = _Jv_StringGetSlot(this);
|
||||||
if (*ptr != NULL && *ptr != DELETED_STRING)
|
if (*ptr != NULL && *ptr != DELETED_STRING)
|
||||||
{
|
{
|
||||||
// See description in unintern() to understand this.
|
// See description in _Jv_FinalizeString() to understand this.
|
||||||
*ptr = (jstring) MASK_PTR (*ptr);
|
*ptr = (jstring) MASK_PTR (*ptr);
|
||||||
return (jstring) UNMASK_PTR (*ptr);
|
return (jstring) UNMASK_PTR (*ptr);
|
||||||
}
|
}
|
||||||
jstring str = this->data == this ? this
|
jstring str = (this->data == this
|
||||||
: _Jv_NewString(JvGetStringChars(this), this->length());
|
? this
|
||||||
|
: _Jv_NewString(JvGetStringChars(this), this->length()));
|
||||||
SET_STRING_IS_INTERNED(str);
|
SET_STRING_IS_INTERNED(str);
|
||||||
strhash_count++;
|
strhash_count++;
|
||||||
*ptr = str;
|
*ptr = str;
|
||||||
// When string is GC'd, clear the slot in the hash table.
|
// When string is GC'd, clear the slot in the hash table.
|
||||||
_Jv_RegisterFinalizer ((void *) str, unintern);
|
_Jv_RegisterStringFinalizer (str);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called by String fake finalizer. */
|
// The fake String finalizer. This is only used when the String has
|
||||||
static void
|
// been intern()d. However, we must check this case, as it might be
|
||||||
unintern (jobject obj)
|
// called by the Reference code for any String.
|
||||||
|
void
|
||||||
|
_Jv_FinalizeString (jobject obj)
|
||||||
{
|
{
|
||||||
JvSynchronize sync (&StringClass);
|
JvSynchronize sync (&StringClass);
|
||||||
|
|
||||||
|
// We might not actually have intern()d any strings at all, if
|
||||||
|
// we're being called from Reference.
|
||||||
|
if (! strhash)
|
||||||
|
return;
|
||||||
|
|
||||||
jstring str = reinterpret_cast<jstring> (obj);
|
jstring str = reinterpret_cast<jstring> (obj);
|
||||||
jstring* ptr = _Jv_StringGetSlot(str);
|
jstring *ptr = _Jv_StringGetSlot(str);
|
||||||
if (*ptr == NULL || *ptr == DELETED_STRING)
|
if (*ptr == NULL || *ptr == DELETED_STRING
|
||||||
|
|| (jobject) UNMASK_PTR (*ptr) != obj)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We assume the lowest bit of the pointer is free for our nefarious
|
// We assume the lowest bit of the pointer is free for our nefarious
|
||||||
|
@ -202,21 +211,21 @@ unintern (jobject obj)
|
||||||
// interning the String. If we subsequently re-intern the same
|
// interning the String. If we subsequently re-intern the same
|
||||||
// String, then we set the bit. When finalizing, if the bit is set
|
// String, then we set the bit. When finalizing, if the bit is set
|
||||||
// then we clear it and re-register the finalizer. We know this is
|
// then we clear it and re-register the finalizer. We know this is
|
||||||
// a safe approach because both intern() and unintern() acquire
|
// a safe approach because both intern() and _Jv_FinalizeString()
|
||||||
// the class lock; this bit can't be manipulated when the lock is
|
// acquire the class lock; this bit can't be manipulated when the
|
||||||
// not held. So if we are finalizing and the bit is clear then we
|
// lock is not held. So if we are finalizing and the bit is clear
|
||||||
// know all references are gone and we can clear the entry in the
|
// then we know all references are gone and we can clear the entry
|
||||||
// hash table. The naive approach of simply clearing the pointer
|
// in the hash table. The naive approach of simply clearing the
|
||||||
// here fails in the case where a request to intern a new string
|
// pointer here fails in the case where a request to intern a new
|
||||||
// with the same contents is made between the time the intern()d
|
// string with the same contents is made between the time the
|
||||||
// string is found to be unreachable and when the finalizer is
|
// intern()d string is found to be unreachable and when the
|
||||||
// actually run. In this case we could clear a pointer to a valid
|
// finalizer is actually run. In this case we could clear a pointer
|
||||||
// string, and future intern() calls for that particular value would
|
// to a valid string, and future intern() calls for that particular
|
||||||
// spuriously fail.
|
// value would spuriously fail.
|
||||||
if (PTR_MASKED (*ptr))
|
if (PTR_MASKED (*ptr))
|
||||||
{
|
{
|
||||||
*ptr = (jstring) UNMASK_PTR (*ptr);
|
*ptr = (jstring) UNMASK_PTR (*ptr);
|
||||||
_Jv_RegisterFinalizer ((void *) obj, unintern);
|
_Jv_RegisterStringFinalizer (obj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -292,8 +301,10 @@ _Jv_NewStringUtf8Const (Utf8Const* str)
|
||||||
jstr->cachedHashCode = hash;
|
jstr->cachedHashCode = hash;
|
||||||
*ptr = jstr;
|
*ptr = jstr;
|
||||||
SET_STRING_IS_INTERNED(jstr);
|
SET_STRING_IS_INTERNED(jstr);
|
||||||
// When string is GC'd, clear the slot in the hash table.
|
// When string is GC'd, clear the slot in the hash table. Note that
|
||||||
_Jv_RegisterFinalizer ((void *) jstr, unintern);
|
// we don't have to call _Jv_RegisterStringFinalizer here, as we
|
||||||
|
// know the new object cannot be referred to by a Reference.
|
||||||
|
_Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString);
|
||||||
return jstr;
|
return jstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,19 @@ remove_from_hash (jobject obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return list head if object is in hash, NULL otherwise.
|
||||||
|
object_list *
|
||||||
|
in_hash (jobject obj)
|
||||||
|
{
|
||||||
|
// The hash table might not yet be initialized.
|
||||||
|
if (hash == NULL)
|
||||||
|
return NULL;
|
||||||
|
object_list *head = find_slot (obj);
|
||||||
|
if (head->reference != obj)
|
||||||
|
return NULL;
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME what happens if an object's finalizer creates a Reference to
|
// FIXME what happens if an object's finalizer creates a Reference to
|
||||||
// the object, and the object has never before been added to the hash?
|
// the object, and the object has never before been added to the hash?
|
||||||
// Madness!
|
// Madness!
|
||||||
|
@ -212,6 +225,29 @@ add_to_hash (java::lang::ref::Reference *the_reference)
|
||||||
*link = n;
|
*link = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a FINALIZE entry if one doesn't exist.
|
||||||
|
static void
|
||||||
|
maybe_add_finalize (object_list *entry, jobject obj)
|
||||||
|
{
|
||||||
|
object_list **link = &entry->next;
|
||||||
|
object_list *iter = *link;
|
||||||
|
while (iter && iter->weight < FINALIZE)
|
||||||
|
{
|
||||||
|
link = &iter->next;
|
||||||
|
iter = *link;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want at most one FINALIZE entry in the queue.
|
||||||
|
if (iter && iter->weight == FINALIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list));
|
||||||
|
n->reference = obj;
|
||||||
|
n->weight = FINALIZE;
|
||||||
|
n->next = *link;
|
||||||
|
*link = n;
|
||||||
|
}
|
||||||
|
|
||||||
// This is called when an object is ready to be finalized. This
|
// This is called when an object is ready to be finalized. This
|
||||||
// actually implements the appropriate Reference semantics.
|
// actually implements the appropriate Reference semantics.
|
||||||
static void
|
static void
|
||||||
|
@ -236,16 +272,21 @@ finalize_referred_to_object (jobject obj)
|
||||||
enum weight w = head->weight;
|
enum weight w = head->weight;
|
||||||
if (w == FINALIZE)
|
if (w == FINALIZE)
|
||||||
{
|
{
|
||||||
|
// Update the list first, as _Jv_FinalizeString might end up
|
||||||
|
// looking at this data structure.
|
||||||
|
list->next = head->next;
|
||||||
|
_Jv_Free (head);
|
||||||
|
|
||||||
// If we have a Reference A to a Reference B, and B is
|
// If we have a Reference A to a Reference B, and B is
|
||||||
// finalized, then we have to take special care to make sure
|
// finalized, then we have to take special care to make sure
|
||||||
// that B is properly deregistered. This is super gross. FIXME
|
// that B is properly deregistered. This is super gross. FIXME
|
||||||
// will it fail if B's finalizer resurrects B?
|
// will it fail if B's finalizer resurrects B?
|
||||||
if (java::lang::ref::Reference::class$.isInstance (obj))
|
if (java::lang::ref::Reference::class$.isInstance (obj))
|
||||||
finalize_reference (obj);
|
finalize_reference (obj);
|
||||||
|
else if (obj->getClass() == &java::lang::String::class$)
|
||||||
|
_Jv_FinalizeString (obj);
|
||||||
else
|
else
|
||||||
_Jv_FinalizeObject (obj);
|
_Jv_FinalizeObject (obj);
|
||||||
list->next = head->next;
|
|
||||||
_Jv_Free (head);
|
|
||||||
}
|
}
|
||||||
else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
|
else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
|
||||||
{
|
{
|
||||||
|
@ -286,6 +327,23 @@ finalize_reference (jobject ref)
|
||||||
_Jv_FinalizeObject (ref);
|
_Jv_FinalizeObject (ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_Jv_RegisterStringFinalizer (jobject str)
|
||||||
|
{
|
||||||
|
// This function might be called before any other Reference method,
|
||||||
|
// so we must ensure the class is initialized.
|
||||||
|
_Jv_InitClass (&java::lang::ref::Reference::class$);
|
||||||
|
JvSynchronize sync (java::lang::ref::Reference::lock);
|
||||||
|
// If the object is in our hash table, then we might need to add a
|
||||||
|
// new FINALIZE entry. Otherwise, we just register an ordinary
|
||||||
|
// finalizer.
|
||||||
|
object_list *entry = in_hash (str);
|
||||||
|
if (entry)
|
||||||
|
maybe_add_finalize (entry, str);
|
||||||
|
else
|
||||||
|
_Jv_RegisterFinalizer ((void *) str, _Jv_FinalizeString);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
::java::lang::ref::Reference::create (jobject ref)
|
::java::lang::ref::Reference::create (jobject ref)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue