summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libjava/ChangeLog15
-rw-r--r--libjava/include/jvm.h6
-rw-r--r--libjava/java/lang/natString.cc59
-rw-r--r--libjava/java/lang/ref/natReference.cc62
4 files changed, 116 insertions, 26 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 1e9525aecf9..d12987a7227 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -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>
* java/net/InetAddress.java:
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index a114e550a15..ed6c61ec50d 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -290,6 +290,12 @@ void _Jv_GCRegisterDisappearingLink (jobject *objp);
implement soft references. */
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. */
long _Jv_GCTotalMemory (void);
/* Return approximation of total free memory. */
diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc
index 6fd928478b5..c87844b0d51 100644
--- a/libjava/java/lang/natString.cc
+++ b/libjava/java/lang/natString.cc
@@ -31,7 +31,6 @@ details. */
#include <gnu/gcj/runtime/StringBuffer.h>
#include <jvm.h>
-static void unintern (jobject);
static jstring* strhash = NULL;
static int strhash_count = 0; /* Number of slots used 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);
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);
return (jstring) UNMASK_PTR (*ptr);
}
- jstring str = this->data == this ? this
- : _Jv_NewString(JvGetStringChars(this), this->length());
+ jstring str = (this->data == this
+ ? this
+ : _Jv_NewString(JvGetStringChars(this), this->length()));
SET_STRING_IS_INTERNED(str);
strhash_count++;
*ptr = str;
// When string is GC'd, clear the slot in the hash table.
- _Jv_RegisterFinalizer ((void *) str, unintern);
+ _Jv_RegisterStringFinalizer (str);
return str;
}
-/* Called by String fake finalizer. */
-static void
-unintern (jobject obj)
+// The fake String finalizer. This is only used when the String has
+// been intern()d. However, we must check this case, as it might be
+// called by the Reference code for any String.
+void
+_Jv_FinalizeString (jobject obj)
{
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* ptr = _Jv_StringGetSlot(str);
- if (*ptr == NULL || *ptr == DELETED_STRING)
+ jstring *ptr = _Jv_StringGetSlot(str);
+ if (*ptr == NULL || *ptr == DELETED_STRING
+ || (jobject) UNMASK_PTR (*ptr) != obj)
return;
// 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
// 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
- // a safe approach because both intern() and unintern() acquire
- // the class lock; this bit can't be manipulated when the lock is
- // not held. So if we are finalizing and the bit is clear then we
- // know all references are gone and we can clear the entry in the
- // hash table. The naive approach of simply clearing the pointer
- // here fails in the case where a request to intern a new string
- // with the same contents is made between the time the intern()d
- // string is found to be unreachable and when the finalizer is
- // actually run. In this case we could clear a pointer to a valid
- // string, and future intern() calls for that particular value would
- // spuriously fail.
+ // a safe approach because both intern() and _Jv_FinalizeString()
+ // acquire the class lock; this bit can't be manipulated when the
+ // lock is not held. So if we are finalizing and the bit is clear
+ // then we know all references are gone and we can clear the entry
+ // in the hash table. The naive approach of simply clearing the
+ // pointer here fails in the case where a request to intern a new
+ // string with the same contents is made between the time the
+ // intern()d string is found to be unreachable and when the
+ // finalizer is actually run. In this case we could clear a pointer
+ // to a valid string, and future intern() calls for that particular
+ // value would spuriously fail.
if (PTR_MASKED (*ptr))
{
*ptr = (jstring) UNMASK_PTR (*ptr);
- _Jv_RegisterFinalizer ((void *) obj, unintern);
+ _Jv_RegisterStringFinalizer (obj);
}
else
{
@@ -292,8 +301,10 @@ _Jv_NewStringUtf8Const (Utf8Const* str)
jstr->cachedHashCode = hash;
*ptr = jstr;
SET_STRING_IS_INTERNED(jstr);
- // When string is GC'd, clear the slot in the hash table.
- _Jv_RegisterFinalizer ((void *) jstr, unintern);
+ // When string is GC'd, clear the slot in the hash table. Note that
+ // 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;
}
diff --git a/libjava/java/lang/ref/natReference.cc b/libjava/java/lang/ref/natReference.cc
index 551bd0809d1..e322ae37cc8 100644
--- a/libjava/java/lang/ref/natReference.cc
+++ b/libjava/java/lang/ref/natReference.cc
@@ -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
// the object, and the object has never before been added to the hash?
// Madness!
@@ -212,6 +225,29 @@ add_to_hash (java::lang::ref::Reference *the_reference)
*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
// actually implements the appropriate Reference semantics.
static void
@@ -236,16 +272,21 @@ finalize_referred_to_object (jobject obj)
enum weight w = head->weight;
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
// finalized, then we have to take special care to make sure
// that B is properly deregistered. This is super gross. FIXME
// will it fail if B's finalizer resurrects B?
if (java::lang::ref::Reference::class$.isInstance (obj))
finalize_reference (obj);
+ else if (obj->getClass() == &java::lang::String::class$)
+ _Jv_FinalizeString (obj);
else
_Jv_FinalizeObject (obj);
- list->next = head->next;
- _Jv_Free (head);
}
else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
{
@@ -287,6 +328,23 @@ finalize_reference (jobject 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
::java::lang::ref::Reference::create (jobject ref)
{
// Nothing says you can't make a Reference with a NULL referent.
OpenPOWER on IntegriCloud