This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
PR java/13273: [3.4 regression] gcj generates call to abstract method
- From: Andrew Haley <aph at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: java-patches at gcc dot gnu dot org
- Date: Fri, 16 Jan 2004 17:06:50 GMT
- Subject: PR java/13273: [3.4 regression] gcj generates call to abstract method
This problem was caused by method lookup being performed in the wrong
order by the bytecode compiler: we were looking at interfaces before
superclasses, whereas the spec is quite clear that we must look first
at superclasses.
I rewrote lookup_do() because there seemed no way to patch it so that
one could be sure it followed the spec.
Checked x86_64-unknown-linux-gnu full bootstrap + full Eclipse build,
no regressions.
Andrew.
2004-01-16 Andrew Haley <aph@redhat.com>
PR java/13273:
* typeck.c (shallow_find_method): New.
(find_method_in_superclasses): New.
(find_method_in_interfaces): New.
(lookup_do): Rewrite.
* java-tree.h (SEARCH_ONLY_INTERFACE): Delete.
* jcf-parse.c (read_class): Save and restore output_class.
* decl.c (java_expand_body): Set output_class from fndecl.
Index: java/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/typeck.c,v
retrieving revision 1.58
diff -p -2 -c -r1.58 typeck.c
*** java/typeck.c 20 Dec 2003 15:38:28 -0000 1.58
--- java/typeck.c 16 Jan 2004 16:25:57 -0000
*************** has_method (tree class, tree method_name
*** 736,739 ****
--- 736,825 ----
}
+ /* Search in class SEARCHED_CLASS, but not its superclasses, for a
+ method matching METHOD_NAME and signature SIGNATURE. A private
+ helper for lookup_do. */
+ static tree
+ shallow_find_method (tree searched_class, int flags, tree method_name,
+ tree signature, tree (*signature_builder) (tree))
+ {
+ tree method;
+ for (method = TYPE_METHODS (searched_class);
+ method != NULL_TREE; method = TREE_CHAIN (method))
+ {
+ tree method_sig = (*signature_builder) (TREE_TYPE (method));
+ if (DECL_NAME (method) == method_name && method_sig == signature)
+ {
+ /* If the caller requires a visible method, then we
+ skip invisible methods here. */
+ if (! (flags & SEARCH_VISIBLE)
+ || ! METHOD_INVISIBLE (method))
+ return method;
+ }
+ }
+ return NULL_TREE;
+ }
+
+ /* Search in the superclasses of SEARCHED_CLASS for a method matching
+ METHOD_NAME and signature SIGNATURE. A private helper for
+ lookup_do. */
+ static tree
+ find_method_in_superclasses (tree searched_class, int flags,
+ tree method_name,
+ tree signature, tree (*signature_builder) (tree))
+ {
+ tree klass;
+ for (klass = CLASSTYPE_SUPER (searched_class); klass != NULL_TREE;
+ klass = CLASSTYPE_SUPER (klass))
+ {
+ tree method;
+ method = shallow_find_method (klass, flags, method_name,
+ signature, signature_builder);
+ if (method != NULL_TREE)
+ return method;
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Search in the interfaces of SEARCHED_CLASS and its superinterfaces
+ for a method matching METHOD_NAME and signature SIGNATURE. A
+ private helper for lookup_do. */
+ static tree
+ find_method_in_interfaces (tree searched_class, int flags, tree method_name,
+ tree signature, tree (*signature_builder) (tree))
+ {
+ int i;
+ int interface_len =
+ TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (searched_class)) - 1;
+
+ for (i = interface_len; i > 0; i--)
+ {
+ tree child =
+ TREE_VEC_ELT (TYPE_BINFO_BASETYPES (searched_class), i);
+ tree iclass = BINFO_TYPE (child);
+
+ /* If the superinterface hasn't been loaded yet, do so now. */
+ if (CLASS_FROM_SOURCE_P (iclass))
+ safe_layout_class (iclass);
+ else if (!CLASS_LOADED_P (iclass))
+ load_class (iclass, 1);
+
+ /* First, we look in ICLASS. If that doesn't work we'll
+ recursively look through all its superinterfaces. */
+ tree method = shallow_find_method (iclass, flags,
+ method_name, signature, signature_builder);
+ if (method != NULL_TREE)
+ return method;
+
+ method = find_method_in_interfaces
+ (iclass, flags, method_name, signature, signature_builder);
+ if (method != NULL_TREE)
+ return method;
+ }
+
+ return NULL_TREE;
+ }
+
+
/* Search in class SEARCHED_CLASS (and its superclasses) for a method
matching METHOD_NAME and signature SIGNATURE. FLAGS control some
*************** has_method (tree class, tree method_name
*** 746,752 ****
superclass.
- SEARCH_ONLY_INTERFACE means don't search ordinary classes, but
- instead only search interfaces and superinterfaces.
-
SEARCH_VISIBLE means skip methods for which METHOD_INVISIBLE is
set.
--- 832,835 ----
*************** lookup_do (tree searched_class, int flag
*** 760,831 ****
{
tree method;
! int first_time = 1;
!
! /* If the incoming class is an interface, then we will only return
! a method declared in an interface context. */
! if (searched_class != NULL_TREE
! && CLASS_INTERFACE (TYPE_NAME (searched_class)))
! flags |= SEARCH_ONLY_INTERFACE;
! while (searched_class != NULL_TREE)
{
- /* First search this class. If we're only searching the
- superclass, skip this. */
- if (! ((flags & SEARCH_SUPER) && first_time))
- {
- for (method = TYPE_METHODS (searched_class);
- method != NULL_TREE; method = TREE_CHAIN (method))
- {
- tree method_sig = (*signature_builder) (TREE_TYPE (method));
- if (DECL_NAME (method) == method_name && method_sig == signature)
- {
- /* If the caller requires a visible method, then we
- skip invisible methods here. */
- if (! (flags & SEARCH_VISIBLE)
- || ! METHOD_INVISIBLE (method))
- return method;
- }
- }
- }
- first_time = 0;
-
- /* Search interfaces, if required. */
- if ((flags & SEARCH_INTERFACE))
- {
- int i;
- int interface_len =
- TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (searched_class)) - 1;
-
- for (i = interface_len; i > 0; i--)
- {
- tree child =
- TREE_VEC_ELT (TYPE_BINFO_BASETYPES (searched_class), i);
- tree iclass = BINFO_TYPE (child);
-
- /* If the superinterface hasn't been loaded yet, do so now. */
- if (CLASS_FROM_SOURCE_P (iclass))
- safe_layout_class (iclass);
- else if (!CLASS_LOADED_P (iclass))
- load_class (iclass, 1);
-
- /* Note that we don't care about SEARCH_VISIBLE here,
- since an interface can never have an invisible
- method. */
- method = lookup_do (iclass, SEARCH_INTERFACE,
- method_name, signature, signature_builder);
- if (method != NULL_TREE)
- return method;
- }
- }
-
- /* If we're only searching for interface methods, then we've
- already searched all the superinterfaces. Our superclass is
- Object, but we don't want to search that. */
- if ((flags & SEARCH_ONLY_INTERFACE))
- break;
searched_class = CLASSTYPE_SUPER (searched_class);
}
! return NULL_TREE;
}
--- 843,876 ----
{
tree method;
!
! if (searched_class == NULL_TREE)
! return NULL_TREE;
! if (flags & SEARCH_SUPER)
{
searched_class = CLASSTYPE_SUPER (searched_class);
+ if (searched_class == NULL_TREE)
+ return NULL_TREE;
}
! /* First look in our own methods. */
! method = shallow_find_method (searched_class, flags, method_name,
! signature, signature_builder);
! if (method)
! return method;
!
! /* Then look in our superclasses. */
! if (! CLASS_INTERFACE (TYPE_NAME (searched_class)))
! method = find_method_in_superclasses (searched_class, flags, method_name,
! signature, signature_builder);
! if (method)
! return method;
!
! /* If that doesn't work, look in our interfaces. */
! if (flags & SEARCH_INTERFACE)
! method = find_method_in_interfaces (searched_class, flags, method_name,
! signature, signature_builder);
!
! return method;
}
Index: java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.175
diff -p -2 -c -r1.175 decl.c
*** java/decl.c 9 Jan 2004 17:08:43 -0000 1.175
--- java/decl.c 16 Jan 2004 16:25:51 -0000
*************** java_expand_body (tree fndecl)
*** 1821,1826 ****
current_function_decl = fndecl;
input_location = DECL_SOURCE_LOCATION (fndecl);
! output_class = DECL_CONTEXT (current_function_decl);
! current_class = DECL_CONTEXT (fndecl);
timevar_push (TV_EXPAND);
--- 1821,1825 ----
current_function_decl = fndecl;
input_location = DECL_SOURCE_LOCATION (fndecl);
! output_class = current_class = DECL_CONTEXT (fndecl);
timevar_push (TV_EXPAND);
Index: java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.193
diff -p -2 -c -r1.193 java-tree.h
*** java/java-tree.h 9 Jan 2004 19:55:13 -0000 1.193
--- java/java-tree.h 16 Jan 2004 16:25:52 -0000
*************** struct lang_type GTY(())
*** 1118,1123 ****
#define SEARCH_INTERFACE 1
#define SEARCH_SUPER 2
! #define SEARCH_ONLY_INTERFACE 4
! #define SEARCH_VISIBLE 8
extern void java_parse_file (int);
--- 1118,1122 ----
#define SEARCH_INTERFACE 1
#define SEARCH_SUPER 2
! #define SEARCH_VISIBLE 4
extern void java_parse_file (int);
Index: java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.156
diff -p -2 -c -r1.156 jcf-parse.c
*** java/jcf-parse.c 9 Jan 2004 17:08:44 -0000 1.156
--- java/jcf-parse.c 16 Jan 2004 16:25:52 -0000
*************** read_class (tree name)
*** 469,472 ****
--- 469,473 ----
tree icv, class = NULL_TREE;
tree save_current_class = current_class;
+ tree save_output_class = output_class;
location_t save_location = input_location;
JCF *save_current_jcf = current_jcf;
*************** read_class (tree name)
*** 546,550 ****
}
! output_class = current_class = save_current_class;
input_location = save_location;
current_jcf = save_current_jcf;
--- 547,552 ----
}
! output_class = save_output_class;
! current_class = save_current_class;
input_location = save_location;
current_jcf = save_current_jcf;