aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2001-10-02 14:31:47 +0000
committerTom Tromey <tromey@redhat.com>2001-10-02 14:31:47 +0000
commit751c3977aa723c462c0c78dfdc862d8e174bb2fc (patch)
tree64d840b2a9f59c9bf181680bd6e70172a0dc5e86
parent8e0659c6ffc9c951302bbadae8697e84aefd13e4 (diff)
* gcj/javaprims.h: Rebuilt class list.
* boehm.cc (_Jv_GCRegisterDisappearingLink): New function. (_Jv_GCCanReclaimSoftReference): New function. * include/jvm.h (_Jv_GCRegisterDisappearingLink): Declare. (_Jv_GCCanReclaimSoftReference): Declare. * java/lang/ref/Reference.java (referent): Now a RawData. (create): Renamed from `created'. Added object argument. (Reference): Don't initialize `referent' here. * Makefile.in: Rebuilt. * Makefile.am (nat_source_files): Added new file. * java/lang/ref/natReference.cc: New file. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@45958 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libjava/ChangeLog12
-rw-r--r--libjava/Makefile.am1
-rw-r--r--libjava/Makefile.in72
-rw-r--r--libjava/boehm.cc13
-rw-r--r--libjava/gcj/javaprims.h1
-rw-r--r--libjava/include/jvm.h7
-rw-r--r--libjava/java/lang/ref/Reference.java25
-rw-r--r--libjava/java/lang/ref/natReference.cc304
8 files changed, 401 insertions, 34 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index ee54950d0d1..e98a20874c9 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,5 +1,17 @@
2001-10-01 Tom Tromey <tromey@redhat.com>
+ * gcj/javaprims.h: Rebuilt class list.
+ * boehm.cc (_Jv_GCRegisterDisappearingLink): New function.
+ (_Jv_GCCanReclaimSoftReference): New function.
+ * include/jvm.h (_Jv_GCRegisterDisappearingLink): Declare.
+ (_Jv_GCCanReclaimSoftReference): Declare.
+ * java/lang/ref/Reference.java (referent): Now a RawData.
+ (create): Renamed from `created'. Added object argument.
+ (Reference): Don't initialize `referent' here.
+ * Makefile.in: Rebuilt.
+ * Makefile.am (nat_source_files): Added new file.
+ * java/lang/ref/natReference.cc: New file.
+
* prims.cc (_Jv_NewMultiArrayUnchecked): New method.
(_Jv_NewMultiArray): Use it. Check each array dimension.
(_Jv_NewMultiArray): Likewise.
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index d86f120fd17..d99334be5e1 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -1511,6 +1511,7 @@ java/lang/natStringBuffer.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natThrowable.cc \
+java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc \
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index 543be3110a1..53599026c50 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -63,16 +63,13 @@ host_alias = @host_alias@
host_triplet = @host@
target_alias = @target_alias@
target_triplet = @target@
-AMTAR = @AMTAR@
AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@
AR = @AR@
AS = @AS@
-AWK = @AWK@
CC = @CC@
COMPPATH = @COMPPATH@
CXX = @CXX@
CXXCPP = @CXXCPP@
-DEPDIR = @DEPDIR@
DIRLTDL = @DIRLTDL@
DIVIDESPEC = @DIVIDESPEC@
DLLTOOL = @DLLTOOL@
@@ -89,7 +86,6 @@ GCSPEC = @GCSPEC@
GCTESTSPEC = @GCTESTSPEC@
HASH_SYNC_SPEC = @HASH_SYNC_SPEC@
INCLTDL = @INCLTDL@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
JC1GCSPEC = @JC1GCSPEC@
LIBFFI = @LIBFFI@
LIBGCJDEBUG = @LIBGCJDEBUG@
@@ -122,34 +118,43 @@ ZINCS = @ZINCS@
ZLIBS = @ZLIBS@
ZLIBSPEC = @ZLIBSPEC@
ZLIBTESTSPEC = @ZLIBTESTSPEC@
-am__include = @am__include@
-am__quote = @am__quote@
here = @here@
-install_sh = @install_sh@
libgcj_basedir = @libgcj_basedir@
mkinstalldirs = @mkinstalldirs@
AUTOMAKE_OPTIONS = foreign
-@TESTSUBDIR_TRUE@SUBDIRS = @TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
-@TESTSUBDIR_FALSE@SUBDIRS = @TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
-@USE_LIBDIR_TRUE@toolexeclibdir = @USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
-@USE_LIBDIR_FALSE@toolexeclibdir = @USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
-@USE_LIBDIR_FALSE@toolexecdir = @USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
-@XLIB_AWT_TRUE@cond_x_ltlibrary = @XLIB_AWT_TRUE@libgcjx.la
-@XLIB_AWT_FALSE@cond_x_ltlibrary =
+@TESTSUBDIR_TRUE@SUBDIRS = \
+@TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
+@TESTSUBDIR_FALSE@SUBDIRS = \
+@TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
+@USE_LIBDIR_TRUE@toolexeclibdir = \
+@USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
+@USE_LIBDIR_FALSE@toolexeclibdir = \
+@USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
+@USE_LIBDIR_FALSE@toolexecdir = \
+@USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
+@XLIB_AWT_TRUE@cond_x_ltlibrary = \
+@XLIB_AWT_TRUE@libgcjx.la
+@XLIB_AWT_FALSE@cond_x_ltlibrary = \
toolexeclib_LTLIBRARIES = libgcj.la $(cond_x_ltlibrary)
toolexeclib_DATA = libgcj.spec
data_DATA = libgcj.jar
-@NATIVE_TRUE@bin_PROGRAMS = @NATIVE_TRUE@jv-convert gij rmic rmiregistry
+@NATIVE_TRUE@bin_PROGRAMS = \
+@NATIVE_TRUE@jv-convert gij rmic rmiregistry
bin_SCRIPTS = addr2name.awk
-@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
-@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_FALSE@jar
-@CANADIAN_FALSE@ZIP = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
-@CANADIAN_TRUE@GCJH = @CANADIAN_TRUE@gcjh
-@CANADIAN_FALSE@GCJH = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
+@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = \
+@CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
+@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = \
+@CANADIAN_TRUE@@NULL_TARGET_FALSE@jar
+@CANADIAN_FALSE@ZIP = \
+@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
+@CANADIAN_TRUE@GCJH = \
+@CANADIAN_TRUE@gcjh
+@CANADIAN_FALSE@GCJH = \
+@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
GCJ_WITH_FLAGS = $(GCJ) --encoding=UTF-8
@@ -169,8 +174,10 @@ AM_CXXFLAGS = -fno-rtti -fnon-call-exceptions \
@LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE \
-DPREFIX="\"$(prefix)\""
-@USING_GCC_TRUE@AM_CFLAGS = @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
-@USING_GCC_FALSE@AM_CFLAGS = @USING_GCC_FALSE@@LIBGCJ_CFLAGS@
+@USING_GCC_TRUE@AM_CFLAGS = \
+@USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
+@USING_GCC_FALSE@AM_CFLAGS = \
+@USING_GCC_FALSE@@LIBGCJ_CFLAGS@
JCFLAGS = -g
JC1FLAGS = @LIBGCJ_JAVAFLAGS@ $(GCJFLAGS)
@@ -239,7 +246,8 @@ extra_headers = java/lang/Object.h java/lang/Class.h
NM = nm
-@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
+@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \
+@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
CONVERT_DIR = gnu/gcj/convert
@@ -1243,6 +1251,7 @@ java/lang/natStringBuffer.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natThrowable.cc \
+java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc \
@@ -1396,12 +1405,12 @@ java/lang/natDouble.lo java/lang/natFloat.lo java/lang/natMath.lo \
java/lang/natObject.lo java/lang/natRuntime.lo java/lang/natString.lo \
java/lang/natStringBuffer.lo java/lang/natSystem.lo \
java/lang/natThread.lo java/lang/natThrowable.lo \
-java/lang/reflect/natArray.lo java/lang/reflect/natConstructor.lo \
-java/lang/reflect/natField.lo java/lang/reflect/natMethod.lo \
-java/net/natInetAddress.lo java/net/natPlainDatagramSocketImpl.lo \
-java/net/natPlainSocketImpl.lo java/text/natCollator.lo \
-java/util/natResourceBundle.lo java/util/zip/natDeflater.lo \
-java/util/zip/natInflater.lo
+java/lang/ref/natReference.lo java/lang/reflect/natArray.lo \
+java/lang/reflect/natConstructor.lo java/lang/reflect/natField.lo \
+java/lang/reflect/natMethod.lo java/net/natInetAddress.lo \
+java/net/natPlainDatagramSocketImpl.lo java/net/natPlainSocketImpl.lo \
+java/text/natCollator.lo java/util/natResourceBundle.lo \
+java/util/zip/natDeflater.lo java/util/zip/natInflater.lo
libgcjx_la_OBJECTS = gnu/gcj/xlib/natClip.lo \
gnu/gcj/xlib/natColormap.lo gnu/gcj/xlib/natDisplay.lo \
gnu/gcj/xlib/natDrawable.lo gnu/gcj/xlib/natFont.lo \
@@ -1445,7 +1454,7 @@ libgcj-test.spec.in libgcj.spec.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP_ENV = --best
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
@@ -1841,6 +1850,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/lang/ref/PhantomReference.P .deps/java/lang/ref/Reference.P \
.deps/java/lang/ref/ReferenceQueue.P \
.deps/java/lang/ref/SoftReference.P .deps/java/lang/ref/WeakReference.P \
+.deps/java/lang/ref/natReference.P \
.deps/java/lang/reflect/AccessibleObject.P \
.deps/java/lang/reflect/Array.P .deps/java/lang/reflect/Constructor.P \
.deps/java/lang/reflect/Field.P \
@@ -2483,7 +2493,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
- cp -pr $$d/$$file $(distdir)/$$file; \
+ cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 27e332b259e..19b58bae908 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -543,6 +543,19 @@ _Jv_AllocTraceOne (jsize size /* includes vtable slot */)
#endif /* JV_HASH_SYNCHRONIZATION */
+void
+_Jv_GCRegisterDisappearingLink (jobject *objp)
+{
+ GC_general_register_disappearing_link ((GC_PTR *) objp, (GC_PTR) *objp);
+}
+
+jboolean
+_Jv_GCCanReclaimSoftReference (jobject obj)
+{
+ // For now, always reclaim soft references. FIXME.
+ return true;
+}
+
#if 0
void
_Jv_InitGC (void)
diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h
index e075bc1d845..d32731558e0 100644
--- a/libjava/gcj/javaprims.h
+++ b/libjava/gcj/javaprims.h
@@ -192,6 +192,7 @@ extern "Java"
class Short;
class StackOverflowError;
class String;
+ class String$CaseInsensitiveComparator;
class StringBuffer;
class StringIndexOutOfBoundsException;
class System;
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index 957869ee581..259d669c650 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -166,6 +166,13 @@ void _Jv_RunGC (void);
/* Disable and enable GC. */
void _Jv_DisableGC (void);
void _Jv_EnableGC (void);
+/* Register a disappearing link. This is a field F which should be
+ cleared when *F is found to be inaccessible. This is used in the
+ implementation of java.lang.ref.Reference. */
+void _Jv_GCRegisterDisappearingLink (jobject *objp);
+/* Return true if OBJECT should be reclaimed. This is used to
+ implement soft references. */
+jboolean _Jv_GCCanReclaimSoftReference (jobject obj);
/* Return approximation of total size of heap. */
long _Jv_GCTotalMemory (void);
diff --git a/libjava/java/lang/ref/Reference.java b/libjava/java/lang/ref/Reference.java
index 23490333b0d..5a6c66324b2 100644
--- a/libjava/java/lang/ref/Reference.java
+++ b/libjava/java/lang/ref/Reference.java
@@ -64,8 +64,21 @@ public abstract class Reference
/**
* The underlying object. This field is handled in a special way by
* the garbage collection.
+ * GCJ LOCAL:
+ * This is a RawData because it must be disguised from the GC.
+ * END GCJ LOCAL
*/
- Object referent;
+ gnu.gcj.RawData referent;
+
+ /**
+ * This is like REFERENT but is not scanned by the GC. We keep a
+ * copy around so that we can see when clear() has been called.
+ * GCJ LOCAL:
+ * This field doesn't exist in Classpath; we use it to detect
+ * clearing.
+ * END GCJ LOCAL
+ */
+ gnu.gcj.RawData copy;
/**
* The queue this reference is registered on. This is null, if this
@@ -97,7 +110,7 @@ public abstract class Reference
*/
Reference(Object ref)
{
- referent = ref;
+ create (ref);
}
/**
@@ -112,11 +125,16 @@ public abstract class Reference
{
if (q == null)
throw new NullPointerException();
- referent = ref;
queue = q;
+ create (ref);
}
/**
+ * Notifies the VM that a new Reference has been created.
+ */
+ private native void create (Object o);
+
+ /**
* Returns the object, this reference refers to.
* @return the object, this reference refers to, or null if the
* reference was cleared.
@@ -138,6 +156,7 @@ public abstract class Reference
public void clear()
{
referent = null;
+ copy = null;
}
/**
diff --git a/libjava/java/lang/ref/natReference.cc b/libjava/java/lang/ref/natReference.cc
new file mode 100644
index 00000000000..8e316ee3850
--- /dev/null
+++ b/libjava/java/lang/ref/natReference.cc
@@ -0,0 +1,304 @@
+// natReference.cc - Native code for References
+
+/* Copyright (C) 2001 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;
+
+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;
+ for (;;)
+ {
+ 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;
+ index = (index + step) & (hash_size - 1);
+ JvAssert (index != start_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);
+ 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);
+ }
+}
+
+// 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 ();
+
+ jobject referent = the_reference->referent;
+ object_list *item = find_slot (referent);
+ if (item->reference == NULL)
+ {
+ // 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;
+ }
+ *link = n;
+ n->next = (*link) ? (*link)->next : NULL;
+}
+
+// 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->weight = DELETED;
+ --hash_count;
+ return;
+ }
+
+ enum weight w = head->weight;
+ if (w == FINALIZE)
+ {
+ // 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
+ _Jv_FinalizeObject (obj);
+ list->next = head->next;
+ _Jv_Free (head);
+ }
+ 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 the copy is already NULL then the user must have
+ // called Reference.clear().
+ if (ref->copy != NULL)
+ {
+ if (w == PHANTOM)
+ ref->referent = ref->copy;
+ else
+ ref->copy = NULL;
+ 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
+::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);
+ jobject *objp = reinterpret_cast<jobject *> (&referent);
+ _Jv_GCRegisterDisappearingLink (objp);
+ add_to_hash (this);
+ }
+}