From d69ad40b46114268021512410165a7ea3b32196c Mon Sep 17 00:00:00 2001
From: aph <aph@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 8 Jun 2006 14:00:43 +0000
Subject: [PATCH] 2006-06-07  Andrew Haley  <aph@redhat.com>

        * include/jvm.h (_Jv_Linker::maybe_adjust_signature): New.
        (_Jv_Linker::uaddr): New.
        * link.cc (resolve_pool_entry): Call search_method_in_superclasses
        instead of an open-coded loop around search_method_in_class.
        (search_method_in_class): Add a new arg, check_perms.
        (search_method_in_superclasses): New.
        (link_symbol_table): Call maybe_adjust_signature() to extract the
        least significnt bit of the signature pointer.  Do this three
        times, for instace method calls, static methods, and interfaces.
        Call search_method_in_superclasses() instead of
        _Jv_LookupDeclaredMethod.
        (typedef uaddr): Delete.



git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@114486 138bc75d-0d04-0410-961f-82ee72b054a4
---
 libjava/ChangeLog     | 15 ++++++++
 libjava/include/jvm.h | 27 ++++++++++++-
 libjava/link.cc       | 89 ++++++++++++++++++++++++++++++-------------
 3 files changed, 104 insertions(+), 27 deletions(-)

diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index f2eef033c3b4..781d0aeedfeb 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,18 @@
+2006-06-07  Andrew Haley  <aph@redhat.com>
+
+	* include/jvm.h (_Jv_Linker::maybe_adjust_signature): New.
+	(_Jv_Linker::uaddr): New.
+	* link.cc (resolve_pool_entry): Call search_method_in_superclasses
+	instead of an open-coded loop around search_method_in_class.
+	(search_method_in_class): Add a new arg, check_perms.
+	(search_method_in_superclasses): New.
+	(link_symbol_table): Call maybe_adjust_signature() to extract the
+	least significnt bit of the signature pointer.  Do this three
+	times, for instace method calls, static methods, and interfaces.
+	Call search_method_in_superclasses() instead of
+	_Jv_LookupDeclaredMethod.
+	(typedef uaddr): Delete.
+	
 2006-06-07  Thomas Fitzsimmons  <fitzsim@redhat.com>
 
 	* scripts/makemake.tcl (emit_bc_rule): Do not skip
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index 542056af5fe2..d99443cf335e 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -239,6 +239,8 @@ namespace gcj
 class _Jv_Linker
 {
 private:
+  typedef unsigned int uaddr __attribute__ ((mode (pointer)));
+
   static _Jv_Field *find_field_helper(jclass, _Jv_Utf8Const *, _Jv_Utf8Const *,
 				      jclass, jclass *);
   static _Jv_Field *find_field(jclass, jclass, jclass *, _Jv_Utf8Const *,
@@ -264,9 +266,32 @@ private:
   static jshort append_partial_itable(jclass, jclass, void **, jshort);
   static _Jv_Method *search_method_in_class (jclass, jclass,
 					     _Jv_Utf8Const *,
-					     _Jv_Utf8Const *);
+					     _Jv_Utf8Const *,
+					     bool check_perms = true);
+  static _Jv_Method *search_method_in_superclasses (jclass cls, jclass klass, 
+						    _Jv_Utf8Const *method_name,
+ 						    _Jv_Utf8Const *method_signature,
+						    jclass *found_class,
+						    bool check_perms = true);
   static void *create_error_method(_Jv_Utf8Const *);
 
+  /* The least significant bit of the signature pointer in a symbol
+     table is set to 1 by the compiler if the reference is "special",
+     i.e. if it is an access to a private field or method.  Extract
+     that bit, clearing it in the address and setting the LSB of
+     SPECIAL accordingly.  */
+  static void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
+  {
+    union {
+      _Jv_Utf8Const *signature;
+      uaddr signature_bits;
+    };
+    signature = s;
+    special = signature_bits & 1;
+    signature_bits -= special;
+    s = signature;
+  }  
+
 public:
 
   static bool has_field_p (jclass, _Jv_Utf8Const *);
diff --git a/libjava/link.cc b/libjava/link.cc
index f95b12878882..5fc82e58b147 100644
--- a/libjava/link.cc
+++ b/libjava/link.cc
@@ -55,8 +55,6 @@ details.  */
 
 using namespace gcj;
 
-typedef unsigned int uaddr __attribute__ ((mode (pointer)));
-
 template<typename T>
 struct aligner
 {
@@ -461,19 +459,11 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy)
 	      goto end_of_method_search;
 	  }
 
-	// Finally, search superclasses. 
-	for (jclass cls = owner->getSuperclass (); cls != 0; 
-	     cls = cls->getSuperclass ())
-	  {
-	    the_method = search_method_in_class (cls, klass, method_name,
-						 method_signature);
-	    if (the_method != 0)
-	      {
-		found_class = cls;
-		break;
-	      }
-	  }
-
+	// Finally, search superclasses.
+	the_method = (search_method_in_superclasses 
+		      (owner->getSuperclass (), klass, method_name, 
+		       method_signature, &found_class));
+	
       end_of_method_search:
     
 	// FIXME: if (cls->loader != klass->loader), then we
@@ -534,11 +524,12 @@ _Jv_Linker::resolve_class_ref (jclass klass, jclass *classref)
 }
 
 // Find a method declared in the cls that is referenced from klass and
-// perform access checks.
+// perform access checks if CHECK_PERMS is true.
 _Jv_Method *
 _Jv_Linker::search_method_in_class (jclass cls, jclass klass, 
 				    _Jv_Utf8Const *method_name, 
-				    _Jv_Utf8Const *method_signature)
+				    _Jv_Utf8Const *method_signature,
+				    bool check_perms)
 {
   using namespace java::lang::reflect;
 
@@ -551,7 +542,7 @@ _Jv_Linker::search_method_in_class (jclass cls, jclass klass,
 				    method_signature)))
 	continue;
 
-      if (_Jv_CheckAccess (klass, cls, method->accflags))
+      if (!check_perms || _Jv_CheckAccess (klass, cls, method->accflags))
 	return method;
       else
 	{
@@ -568,6 +559,30 @@ _Jv_Linker::search_method_in_class (jclass cls, jclass klass,
   return 0;
 }
 
+// Like search_method_in_class, but work our way up the superclass
+// chain.
+_Jv_Method *
+_Jv_Linker::search_method_in_superclasses (jclass cls, jclass klass, 
+					   _Jv_Utf8Const *method_name, 
+					   _Jv_Utf8Const *method_signature,
+					   jclass *found_class, bool check_perms)
+{
+  _Jv_Method *the_method = NULL;
+
+  for ( ; cls != 0; cls = cls->getSuperclass ())
+    {
+      the_method = search_method_in_class (cls, klass, method_name,
+					   method_signature, check_perms);
+      if (the_method != 0)
+	{
+	  if (found_class)
+	    *found_class = cls;
+	  break;
+	}
+    }
+  
+  return the_method;
+}
 
 #define INITIAL_IOFFSETS_LEN 4
 #define INITIAL_IFACES_LEN 4
@@ -1076,6 +1091,8 @@ _Jv_Linker::link_symbol_table (jclass klass)
       _Jv_Method *meth = NULL;            
 
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       if (target_class == NULL)
 	throw new java::lang::NoClassDefFoundError 
@@ -1101,8 +1118,15 @@ _Jv_Linker::link_symbol_table (jclass klass)
 	  // it out now.
 	  wait_for_state(target_class, JV_STATE_PREPARED);
 
-	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
-					  sym.signature);
+	  try
+	    {
+	      meth = (search_method_in_superclasses 
+		      (target_class, klass, sym.name, signature, 
+		       NULL, special == 0));
+	    }
+	  catch (::java::lang::IllegalAccessError *e)
+	    {
+	    }
 
 	  // Every class has a throwNoSuchMethodErrorIndex method that
 	  // it inherits from java.lang.Object.  Find its vtable
@@ -1158,7 +1182,7 @@ _Jv_Linker::link_symbol_table (jclass klass)
 	try
 	  {
 	    the_field = find_field (klass, target_class, &found_class,
-				    sym.name, sym.signature);
+				    sym.name, signature);
 	    if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
 	      throw new java::lang::IncompatibleClassChangeError;
 	    else
@@ -1185,7 +1209,10 @@ _Jv_Linker::link_symbol_table (jclass klass)
         _Jv_FindClassNoException (sym.class_name, klass->loader);
 
       _Jv_Method *meth = NULL;            
+
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       // ??? Setting this pointer to null will at least get us a
       // NullPointerException
@@ -1193,7 +1220,7 @@ _Jv_Linker::link_symbol_table (jclass klass)
 
       // If the target class is missing we prepare a function call
       // that throws a NoClassDefFoundError and store the address of
-      // that newly prepare method in the atable. The user can run
+      // that newly prepared method in the atable. The user can run
       // code in classes where the missing class is part of the
       // execution environment as long as it is never referenced.
       if (target_class == NULL)
@@ -1219,8 +1246,15 @@ _Jv_Linker::link_symbol_table (jclass klass)
 	      throw new VerifyError(sb->toString());
 	    }
 
-	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
-					  sym.signature);
+	  try
+	    {
+	      meth = (search_method_in_superclasses 
+		      (target_class, klass, sym.name, signature, 
+		       NULL, special == 0));
+	    }
+	  catch (::java::lang::IllegalAccessError *e)
+	    {
+	    }
 
 	  if (meth != NULL)
 	    {
@@ -1250,7 +1284,7 @@ _Jv_Linker::link_symbol_table (jclass klass)
 	wait_for_state(target_class, JV_STATE_PREPARED);
 	jclass found_class;
 	_Jv_Field *the_field = find_field (klass, target_class, &found_class,
-					   sym.name, sym.signature);
+					   sym.name, signature);
 	if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
 	  klass->atable->addresses[index] = the_field->u.addr;
 	else
@@ -1270,14 +1304,17 @@ _Jv_Linker::link_symbol_table (jclass klass)
        ++index)
     {
       jclass target_class = _Jv_FindClass (sym.class_name, klass->loader);
+
       _Jv_Utf8Const *signature = sym.signature;
+      uaddr special;
+      maybe_adjust_signature (signature, special);
 
       jclass cls;
       int i;
 
       wait_for_state(target_class, JV_STATE_LOADED);
       bool found = _Jv_getInterfaceMethod (target_class, cls, i,
-					   sym.name, sym.signature);
+					   sym.name, signature);
 
       if (found)
 	{
-- 
GitLab