summaryrefslogtreecommitdiff
path: root/libjava/java/lang/ref
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/lang/ref')
-rw-r--r--libjava/java/lang/ref/PhantomReference.h20
-rw-r--r--libjava/java/lang/ref/Reference.h45
-rw-r--r--libjava/java/lang/ref/Reference.java204
-rw-r--r--libjava/java/lang/ref/ReferenceQueue.h31
-rw-r--r--libjava/java/lang/ref/SoftReference.h21
-rw-r--r--libjava/java/lang/ref/WeakReference.h20
-rw-r--r--libjava/java/lang/ref/natReference.cc377
7 files changed, 718 insertions, 0 deletions
diff --git a/libjava/java/lang/ref/PhantomReference.h b/libjava/java/lang/ref/PhantomReference.h
new file mode 100644
index 000000000..0c8a823d4
--- /dev/null
+++ b/libjava/java/lang/ref/PhantomReference.h
@@ -0,0 +1,20 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __java_lang_ref_PhantomReference__
+#define __java_lang_ref_PhantomReference__
+
+#pragma interface
+
+#include <java/lang/ref/Reference.h>
+
+class java::lang::ref::PhantomReference : public ::java::lang::ref::Reference
+{
+
+public:
+ PhantomReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *);
+ virtual ::java::lang::Object * get();
+ static ::java::lang::Class class$;
+};
+
+#endif // __java_lang_ref_PhantomReference__
diff --git a/libjava/java/lang/ref/Reference.h b/libjava/java/lang/ref/Reference.h
new file mode 100644
index 000000000..3eeaf65c6
--- /dev/null
+++ b/libjava/java/lang/ref/Reference.h
@@ -0,0 +1,45 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __java_lang_ref_Reference__
+#define __java_lang_ref_Reference__
+
+#pragma interface
+
+#include <java/lang/Object.h>
+extern "Java"
+{
+ namespace gnu
+ {
+ namespace gcj
+ {
+ class RawData;
+ }
+ }
+}
+
+class java::lang::ref::Reference : public ::java::lang::Object
+{
+
+public: // actually package-private
+ Reference(::java::lang::Object *);
+ Reference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *);
+private:
+ void create(::java::lang::Object *);
+public:
+ virtual ::java::lang::Object * get();
+ virtual void clear();
+ virtual jboolean isEnqueued();
+ virtual jboolean enqueue();
+public: // actually package-private
+ ::gnu::gcj::RawData * __attribute__((aligned(__alignof__( ::java::lang::Object)))) referent;
+ ::gnu::gcj::RawData * copy;
+ jboolean cleared;
+ ::java::lang::ref::ReferenceQueue * queue;
+ ::java::lang::ref::Reference * nextOnQueue;
+ static ::java::lang::Object * lock;
+public:
+ static ::java::lang::Class class$;
+};
+
+#endif // __java_lang_ref_Reference__
diff --git a/libjava/java/lang/ref/Reference.java b/libjava/java/lang/ref/Reference.java
new file mode 100644
index 000000000..a5184cee8
--- /dev/null
+++ b/libjava/java/lang/ref/Reference.java
@@ -0,0 +1,204 @@
+/* java.lang.ref.Reference
+ Copyright (C) 1999, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.lang.ref;
+
+/**
+ * This is the base class of all references. A reference allows
+ * refering to an object without preventing the garbage collector to
+ * collect it. The only way to get the referred object is via the
+ * <code>get()</code>-method. This method will return
+ * <code>null</code> if the object was collected. <br>
+ *
+ * A reference may be registered with a queue. When a referred
+ * element gets collected the reference will be put on the queue, so
+ * that you will be notified. <br>
+ *
+ * There are currently three types of references: soft reference,
+ * weak reference and phantom reference. <br>
+ *
+ * Soft references will be cleared if the garbage collector is told
+ * to free some memory and there are no unreferenced or weakly referenced
+ * objects. It is useful for caches. <br>
+ *
+ * Weak references will be cleared as soon as the garbage collector
+ * determines that the refered object is only weakly reachable. They
+ * are useful as keys in hashtables (see <code>WeakHashtable</code>) as
+ * you get notified when nobody has the key anymore.
+ *
+ * Phantom references don't prevent finalization. If an object is only
+ * phantom reachable, it will be finalized, and the reference will be
+ * enqueued, but not cleared. Since you mustn't access an finalized
+ * object, the <code>get</code> method of a phantom reference will never
+ * work. It is useful to keep track, when an object is finalized.
+ *
+ * @author Jochen Hoenicke
+ * @see java.util.WeakHashtable
+ */
+public abstract class Reference<T>
+{
+ /**
+ * The underlying object. This field is handled in a special way by
+ * the garbage collector.
+ * GCJ LOCAL:
+ * This is a RawData because it must be disguised from the GC.
+ * END GCJ LOCAL
+ */
+ gnu.gcj.RawData referent;
+
+ /**
+ * This is like REFERENT but is not scanned by the GC. We keep a
+ * copy around so that we can clean up our internal data structure
+ * even after clear() is called.
+ * GCJ LOCAL:
+ * This field doesn't exist in Classpath.
+ * END GCJ LOCAL
+ */
+ gnu.gcj.RawData copy;
+
+ /**
+ * Set to true if {@link #clear()} is called.
+ * GCJ LOCAL:
+ * This field doesn't exist in Classpath. It is used internally in
+ * natReference.cc, which enqueues the reference unless it is true
+ * (has been cleared).
+ * END GCJ LOCAL
+ */
+ boolean cleared = false;
+
+ /**
+ * The queue this reference is registered on. This is null, if this
+ * wasn't registered to any queue or reference was already enqueued.
+ */
+ ReferenceQueue<? super T> queue;
+
+ /**
+ * Link to the next entry on the queue. If this is null, this
+ * reference is not enqueued. Otherwise it points to the next
+ * reference. The last reference on a queue will point to itself
+ * (not to null, that value is used to mark a not enqueued
+ * reference).
+ */
+ Reference nextOnQueue;
+
+ /**
+ * This lock should be taken by the garbage collector, before
+ * determining reachability. It will prevent the get()-method to
+ * return the reference so that reachability doesn't change.
+ */
+ static Object lock = new Object();
+
+ /**
+ * Creates a new reference that is not registered to any queue.
+ * Since it is package private, it is not possible to overload this
+ * class in a different package.
+ * @param referent the object we refer to.
+ */
+ Reference(T ref)
+ {
+ create (ref);
+ }
+
+ /**
+ * Creates a reference that is registered to a queue. Since this is
+ * package private, it is not possible to overload this class in a
+ * different package.
+ * @param referent the object we refer to.
+ * @param q the reference queue to register on.
+ * @exception NullPointerException if q is null.
+ */
+ Reference(T ref, ReferenceQueue<? super T> q)
+ {
+ if (q == null)
+ throw new NullPointerException();
+ queue = q;
+ create (ref);
+ }
+
+ /**
+ * Notifies the VM that a new Reference has been created.
+ */
+ private native void create (T o);
+
+ /**
+ * Returns the object, this reference refers to.
+ * @return the object, this reference refers to, or null if the
+ * reference was cleared.
+ */
+ public native T get();
+
+ /**
+ * Clears the reference, so that it doesn't refer to its object
+ * anymore. For soft and weak references this is called by the
+ * garbage collector. For phantom references you should call
+ * this when enqueuing the reference.
+ */
+ public void clear()
+ {
+ // Must synchronize so changes are visible in finalizer thread.
+ synchronized (lock)
+ {
+ referent = null;
+ cleared = true;
+ }
+ }
+
+ /**
+ * Tells if the object is enqueued on a reference queue.
+ * @return true if it is enqueued, false otherwise.
+ */
+ public boolean isEnqueued()
+ {
+ return nextOnQueue != null;
+ }
+
+ /**
+ * Enqueue an object on a reference queue. This is normally executed
+ * by the garbage collector.
+ */
+ public boolean enqueue()
+ {
+ if (queue != null && nextOnQueue == null)
+ {
+ queue.enqueue(this);
+ queue = null;
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libjava/java/lang/ref/ReferenceQueue.h b/libjava/java/lang/ref/ReferenceQueue.h
new file mode 100644
index 000000000..bd4a9d8b7
--- /dev/null
+++ b/libjava/java/lang/ref/ReferenceQueue.h
@@ -0,0 +1,31 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __java_lang_ref_ReferenceQueue__
+#define __java_lang_ref_ReferenceQueue__
+
+#pragma interface
+
+#include <java/lang/Object.h>
+
+class java::lang::ref::ReferenceQueue : public ::java::lang::Object
+{
+
+public:
+ ReferenceQueue();
+ virtual ::java::lang::ref::Reference * poll();
+public: // actually package-private
+ virtual jboolean enqueue(::java::lang::ref::Reference *);
+private:
+ ::java::lang::ref::Reference * dequeue();
+public:
+ virtual ::java::lang::ref::Reference * remove(jlong);
+ virtual ::java::lang::ref::Reference * remove();
+private:
+ ::java::lang::ref::Reference * __attribute__((aligned(__alignof__( ::java::lang::Object)))) first;
+ ::java::lang::Object * lock;
+public:
+ static ::java::lang::Class class$;
+};
+
+#endif // __java_lang_ref_ReferenceQueue__
diff --git a/libjava/java/lang/ref/SoftReference.h b/libjava/java/lang/ref/SoftReference.h
new file mode 100644
index 000000000..faa98e7bd
--- /dev/null
+++ b/libjava/java/lang/ref/SoftReference.h
@@ -0,0 +1,21 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __java_lang_ref_SoftReference__
+#define __java_lang_ref_SoftReference__
+
+#pragma interface
+
+#include <java/lang/ref/Reference.h>
+
+class java::lang::ref::SoftReference : public ::java::lang::ref::Reference
+{
+
+public:
+ SoftReference(::java::lang::Object *);
+ SoftReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *);
+ virtual ::java::lang::Object * get();
+ static ::java::lang::Class class$;
+};
+
+#endif // __java_lang_ref_SoftReference__
diff --git a/libjava/java/lang/ref/WeakReference.h b/libjava/java/lang/ref/WeakReference.h
new file mode 100644
index 000000000..b540274d3
--- /dev/null
+++ b/libjava/java/lang/ref/WeakReference.h
@@ -0,0 +1,20 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __java_lang_ref_WeakReference__
+#define __java_lang_ref_WeakReference__
+
+#pragma interface
+
+#include <java/lang/ref/Reference.h>
+
+class java::lang::ref::WeakReference : public ::java::lang::ref::Reference
+{
+
+public:
+ WeakReference(::java::lang::Object *);
+ WeakReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *);
+ static ::java::lang::Class class$;
+};
+
+#endif // __java_lang_ref_WeakReference__
diff --git a/libjava/java/lang/ref/natReference.cc b/libjava/java/lang/ref/natReference.cc
new file mode 100644
index 000000000..ac7272cf5
--- /dev/null
+++ b/libjava/java/lang/ref/natReference.cc
@@ -0,0 +1,377 @@
+// natReference.cc - Native code for References
+
+/* Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+// Written by Tom Tromey <tromey@redhat.com>
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java/lang/Throwable.h>
+#include <java/lang/ref/Reference.h>
+#include <java/lang/ref/SoftReference.h>
+#include <java/lang/ref/WeakReference.h>
+#include <java/lang/ref/PhantomReference.h>
+#include <java/lang/ref/ReferenceQueue.h>
+
+static void finalize_reference (jobject ref);
+static void finalize_referred_to_object (jobject obj);
+
+
+
+enum weight
+{
+ SOFT = 0,
+ WEAK = 1,
+ FINALIZE = 2,
+ PHANTOM = 3,
+
+ // This is used to mark the head of a list.
+ HEAD = 4,
+
+ // This is used to mark a deleted item.
+ DELETED = 5
+};
+
+// Objects of this type are used in the hash table to keep track of
+// the mapping between a finalizable object and the various References
+// which refer to it.
+struct object_list
+{
+ // The reference object. This is NULL for FINALIZE weight.
+ jobject reference;
+
+ // The weight of this object.
+ enum weight weight;
+
+ // Next in list.
+ object_list *next;
+};
+
+// Hash table used to hold mapping from object to References. The
+// object_list item in the hash holds the object itself in the
+// reference field; chained to it are all the references sorted in
+// order of weight (lowest first).
+static object_list *hash = NULL;
+
+// Number of slots used in HASH.
+static int hash_count = 0;
+
+// Number of slots total in HASH. Must be power of 2.
+static int hash_size = 0;
+
+#define DELETED_REFERENCE ((jobject) -1)
+
+static object_list *
+find_slot (jobject key)
+{
+ jint hcode = _Jv_HashCode (key);
+ /* step must be non-zero, and relatively prime with hash_size. */
+ jint step = (hcode ^ (hcode >> 16)) | 1;
+ int start_index = hcode & (hash_size - 1);
+ int index = start_index;
+ int deleted_index = -1;
+ do
+ {
+ object_list *ptr = &hash[index];
+ if (ptr->reference == key)
+ return ptr;
+ else if (ptr->reference == NULL)
+ {
+ if (deleted_index == -1)
+ return ptr;
+ else
+ return &hash[deleted_index];
+ }
+ else if (ptr->weight == DELETED)
+ {
+ deleted_index = index;
+ JvAssert (ptr->reference == DELETED_REFERENCE);
+ }
+ index = (index + step) & (hash_size - 1);
+ }
+ while (index != start_index);
+ // Note that we can have INDEX == START_INDEX if the table has no
+ // NULL entries but does have DELETED entries.
+ JvAssert (deleted_index >= 0);
+ return &hash[deleted_index];
+}
+
+static void
+rehash ()
+{
+ if (hash == NULL)
+ {
+ hash_size = 1024;
+ hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
+ memset (hash, 0, hash_size * sizeof (object_list));
+ }
+ else
+ {
+ object_list *old = hash;
+ int i = hash_size;
+
+ hash_size *= 2;
+ hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
+ memset (hash, 0, hash_size * sizeof (object_list));
+
+ while (--i >= 0)
+ {
+ if (old[i].reference == NULL || old[i].weight == DELETED)
+ continue;
+ object_list *newslot = find_slot (old[i].reference);
+ *newslot = old[i];
+ }
+
+ _Jv_Free (old);
+ }
+}
+
+// Remove a Reference.
+static void
+remove_from_hash (jobject obj)
+{
+ java::lang::ref::Reference *ref
+ = reinterpret_cast<java::lang::ref::Reference *> (obj);
+ object_list *head = find_slot (ref->copy);
+
+ // We might have found a new slot. We can just ignore that here.
+ if (head->reference != ref->copy)
+ return;
+
+ object_list **link = &head->next;
+ head = head->next;
+
+ while (head && head->reference != ref)
+ {
+ link = &head->next;
+ head = head->next;
+ }
+
+ // Remove the slot.
+ if (head)
+ {
+ *link = head->next;
+ _Jv_Free (head);
+ }
+}
+
+// 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!
+
+// Add an item to the hash table. If the item is new, we also add a
+// finalizer item. We keep items in the hash table until they are
+// completely collected; this lets us know when an item is new, even
+// if it has been resurrected after its finalizer has been run.
+static void
+add_to_hash (java::lang::ref::Reference *the_reference)
+{
+ JvSynchronize sync (java::lang::ref::Reference::lock);
+
+ if (3 * hash_count >= 2 * hash_size)
+ rehash ();
+
+ // Use `copy' here because the `referent' field has been cleared.
+ jobject referent = the_reference->copy;
+ object_list *item = find_slot (referent);
+ if (item->reference == NULL || item->reference == DELETED_REFERENCE)
+ {
+ // New item, so make an entry for the finalizer.
+ item->reference = referent;
+ item->weight = HEAD;
+
+ item->next = (object_list *) _Jv_Malloc (sizeof (object_list));
+ item->next->reference = NULL;
+ item->next->weight = FINALIZE;
+ item->next->next = NULL;
+ ++hash_count;
+ }
+
+ object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list));
+ n->reference = the_reference;
+
+ enum weight w = PHANTOM;
+ if (java::lang::ref::SoftReference::class$.isInstance (the_reference))
+ w = SOFT;
+ else if (java::lang::ref::WeakReference::class$.isInstance (the_reference))
+ w = WEAK;
+ n->weight = w;
+
+ object_list **link = &item->next;
+ object_list *iter = *link;
+ while (iter && iter->weight < n->weight)
+ {
+ link = &iter->next;
+ iter = *link;
+ }
+ n->next = *link;
+ *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
+finalize_referred_to_object (jobject obj)
+{
+ JvSynchronize sync (java::lang::ref::Reference::lock);
+
+ object_list *list = find_slot (obj);
+ object_list *head = list->next;
+ if (head == NULL)
+ {
+ // We have a truly dead object: the object's finalizer has been
+ // run, all the object's references have been processed, and the
+ // object is unreachable. There is, at long last, no way to
+ // resurrect it.
+ list->reference = DELETED_REFERENCE;
+ list->weight = DELETED;
+ --hash_count;
+ return;
+ }
+
+ 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);
+ }
+ else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
+ {
+ // If we just decided to reclaim a soft reference, we might as
+ // well do all the weak references at the same time.
+ if (w == SOFT)
+ w = WEAK;
+
+ while (head && head->weight <= w)
+ {
+ java::lang::ref::Reference *ref
+ = reinterpret_cast<java::lang::ref::Reference *> (head->reference);
+ if (! ref->cleared)
+ ref->enqueue ();
+
+ object_list *next = head->next;
+ _Jv_Free (head);
+ head = next;
+ }
+ list->next = head;
+ }
+
+ // Re-register this finalizer. We always re-register because we
+ // can't know until the next collection cycle whether or not the
+ // object is truly unreachable.
+ _Jv_RegisterFinalizer (obj, finalize_referred_to_object);
+}
+
+// This is called when a Reference object is finalized. If there is a
+// Reference pointing to this Reference then that case is handled by
+// finalize_referred_to_object.
+static void
+finalize_reference (jobject ref)
+{
+ JvSynchronize sync (java::lang::ref::Reference::lock);
+ remove_from_hash (ref);
+ // The user might have a subclass of Reference with a finalizer.
+ _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
+::java::lang::ref::Reference::create (jobject ref)
+{
+ // Nothing says you can't make a Reference with a NULL referent.
+ // But there's nothing to do in such a case.
+ referent = reinterpret_cast<gnu::gcj::RawData *> (ref);
+ copy = referent;
+ if (referent != NULL)
+ {
+ JvSynchronize sync (java::lang::ref::Reference::lock);
+ // `this' is a new Reference object. We register a new
+ // finalizer for pointed-to object and we arrange a special
+ // finalizer for ourselves as well.
+ _Jv_RegisterFinalizer (this, finalize_reference);
+ _Jv_RegisterFinalizer (referent, finalize_referred_to_object);
+ gnu::gcj::RawData **p = &referent;
+ _Jv_GCRegisterDisappearingLink ((jobject *) p);
+ add_to_hash (this);
+ }
+}
+
+::java::lang::Object *
+::java::lang::ref::Reference::get()
+{
+ JvSynchronize sync (lock);
+ return referent;
+}