diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 9c1f1c0e92be4e8f60748fb616eba1b8af3b9eb0..044f72442ba52782b1cc93ce21029e840b76f18e 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,12 @@
+2002-01-30  Tom Tromey  <tromey@redhat.com>
+
+	* verify.cc (handle_ret_insn): Check for subroutine merge here...
+	(state::merge): ... not here.
+	(subr_entry_info): New structure.
+	(entry_points): New field.
+	(~_Jv_BytecodeVerifier): Correctly free jsr_ptrs.  Free
+	entry_points.
+
 2002-01-29  Tom Tromey  <tromey@redhat.com>
 
 	* java/awt/List.java (addNotify): Correctly check to see if peer
diff --git a/libjava/verify.cc b/libjava/verify.cc
index 910083104877b228520ac8255ab8ebb2eef4db55..1035cdaf4c8474b0877fb6ec6d0dc8eb99df6f82 100644
--- a/libjava/verify.cc
+++ b/libjava/verify.cc
@@ -56,6 +56,7 @@ private:
   struct state;
   struct type;
   struct subr_info;
+  struct subr_entry_info;
   struct linked_utf8;
 
   // The current PC.
@@ -84,6 +85,11 @@ private:
   // of all calling `jsr's at at each jsr target.
   subr_info **jsr_ptrs;
 
+  // We keep a linked list of entries which map each `ret' instruction
+  // to its unique subroutine entry point.  We expect that there won't
+  // be many `ret' instructions, so a linked list is ok.
+  subr_entry_info *entry_points;
+
   // The current top of the stack, in terms of slots.
   int stacktop;
   // The current depth of the stack.  This will be larger than
@@ -273,6 +279,18 @@ private:
     subr_info *next;
   };
 
+  // This is used to keep track of which subroutine entry point
+  // corresponds to which `ret' instruction.
+  struct subr_entry_info
+  {
+    // PC of the subroutine entry point.
+    int pc;
+    // PC of the `ret' instruction.
+    int ret_pc;
+    // Link.
+    subr_entry_info *next;
+  };
+
   // The `type' class is used to represent a single type in the
   // verifier.
   struct type
@@ -886,9 +904,9 @@ private:
       if (this_type.isinitialized ())
 	this_type = state_old->this_type;
 
-      // Merge subroutine states.  *THIS and *STATE_OLD must be in the
-      // same subroutine.  Also, recursive subroutine calls must be
-      // avoided.
+      // Merge subroutine states.  Here we just keep track of what
+      // subroutine we think we're in.  We only check for a merge
+      // (which is invalid) when we see a `ret'.
       if (subroutine == state_old->subroutine)
 	{
 	  // Nothing.
@@ -898,11 +916,13 @@ private:
 	  subroutine = state_old->subroutine;
 	  changed = true;
 	}
-      // If we're handling the result of an unmerged `ret', then we
-      // can't trust that it has the correct PC setting.  So in this
-      // case we ignore what might otherwise look like a merge error.
-      else if (! state_old->is_unmerged_ret_state (max_locals))
-	verifier->verify_fail ("subroutines merged");
+      else
+	{
+	  // If the subroutines differ, indicate that the state
+	  // changed.  This is needed to detect when subroutines have
+	  // merged.
+	  changed = true;
+	}
 
       // Merge stacks.
       if (state_old->stacktop != stacktop)
@@ -1329,6 +1349,24 @@ private:
     if (csub == 0)
       verify_fail ("no subroutine");
 
+    // Check to see if we've merged subroutines.
+    subr_entry_info *entry;
+    for (entry = entry_points; entry != NULL; entry = entry->next)
+      {
+	if (entry->ret_pc == start_PC)
+	  break;
+      }
+    if (entry == NULL)
+      {
+	entry = (subr_entry_info *) _Jv_Malloc (sizeof (subr_entry_info));
+	entry->pc = csub;
+	entry->ret_pc = start_PC;
+	entry->next = entry_points;
+	entry_points = entry;
+      }
+    else if (entry->pc != csub)
+      verify_fail ("subroutines merged");
+
     for (subr_info *subr = jsr_ptrs[csub]; subr != NULL; subr = subr->next)
       {
 	// Temporarily modify the current state so it looks like we're
@@ -2893,6 +2931,7 @@ public:
     flags = NULL;
     jsr_ptrs = NULL;
     utf8_list = NULL;
+    entry_points = NULL;
   }
 
   ~_Jv_BytecodeVerifier ()
@@ -2901,8 +2940,25 @@ public:
       _Jv_Free (states);
     if (flags)
       _Jv_Free (flags);
+
     if (jsr_ptrs)
-      _Jv_Free (jsr_ptrs);
+      {
+	for (int i = 0; i < current_method->code_length; ++i)
+	  {
+	    if (jsr_ptrs[i] != NULL)
+	      {
+		subr_info *info = jsr_ptrs[i];
+		while (info != NULL)
+		  {
+		    subr_info *next = info->next;
+		    _Jv_Free (info);
+		    info = next;
+		  }
+	      }
+	  }
+	_Jv_Free (jsr_ptrs);
+      }
+
     while (utf8_list != NULL)
       {
 	linked_utf8 *n = utf8_list->next;
@@ -2910,6 +2966,13 @@ public:
 	_Jv_Free (utf8_list);
 	utf8_list = n;
       }
+
+    while (entry_points != NULL)
+      {
+	subr_entry_info *next = entry_points->next;
+	_Jv_Free (entry_points);
+	entry_points = next;
+      }
   }
 };