javaprims.h: Rebuilt class list.
authorTom Tromey <tromey@redhat.com>
Tue, 2 Oct 2001 14:31:47 +0000 (14:31 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Tue, 2 Oct 2001 14:31:47 +0000 (14:31 +0000)
* 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.

From-SVN: r45958

libjava/ChangeLog
libjava/Makefile.am
libjava/Makefile.in
libjava/boehm.cc
libjava/gcj/javaprims.h
libjava/include/jvm.h
libjava/java/lang/ref/Reference.java
libjava/java/lang/ref/natReference.cc [new file with mode: 0644]

index ee54950..e98a208 100644 (file)
@@ -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.
index d86f120..d99334b 100644 (file)
@@ -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 \
index 543be31..5359902 100644 (file)
@@ -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 \
index 27e332b..19b58ba 100644 (file)
@@ -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)
index e075bc1..d327315 100644 (file)
@@ -192,6 +192,7 @@ extern "Java"
       class Short;
       class StackOverflowError;
       class String;
+      class String$CaseInsensitiveComparator;
       class StringBuffer;
       class StringIndexOutOfBoundsException;
       class System;
index 957869e..259d669 100644 (file)
@@ -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);
index 2349033..5a6c663 100644 (file)
@@ -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 (file)
index 0000000..8e316ee
--- /dev/null
@@ -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);
+
+\f
+
+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);
+    }
+}