From 23a79c61921246f3d84df2503555208f2683203e Mon Sep 17 00:00:00 2001 From: Alexandre Petit-Bianco Date: Tue, 24 Nov 1998 09:57:41 -0800 Subject: [PATCH] [multiple changes] Tue Nov 24 17:06:38 1998 Per Bothner * (generate_classfile): Always write class access flag with ACC_SUPER set. Tue Nov 24 16:34:33 1998 Alexandre Petit-Bianco * class.c (maybe_layout_super_class): New function. (layout_class): Reorganized. Loop on class methods dispatched into a new function. Call maybe_layout_super_class. (layout_class_methods, layout_class_method): New functions. * expr.c (expand_java_NEW): Call layout_class_methods on loaded class. (expand_invoke): Likewise. * java-tree.h (all_class_list): New global variable declared. (layout_class_methods, layout_class_method): New function prototypes. (LAYOUT_SEEN_CLASS_METHODS): New macro. * jcf-parse.c (all_class_list): New global variable. (load_class): Extended what class_or_name can be. Use parser context mechanism to save globals before calling jcf_parse. (jcf_parse_source): Don't parse twice if HAS_BEEN_ALREADY_PARSED_P is set on the file name. (jcf_parse): Layout class methods when Object is loaded, otherwise record class in all_class_list for delayed method layout. (parse_class_file): Use LAYOUT_SEEN_CLASS_METHODS. * lang.c (put_decl_node): Decode into the decl context class name. * lex.c (java_allocate_new_line): Use xmalloc. * parse.h (INCOMPLETE_TYPE_P): Redefined to work with incomplete pointers, not TREE_LIST elements. (struct parser_ctxt): Fixed comment indentations, added comments and reordered some fields. (java_check_methods): Function prototype removed. * parse.y (java_push_parser_context): Use xmalloc. (java_parser_context_restore_global): Pop extra pushed ctxp only when there's nothing next. (maybe_create_class_interface_decl): Fixed comment, add new created class decl to all_class_list. (method_header): Use GET_REAL_TYPE on argument's types. (method_declarator): Use GET_REAL_TYPE, change type to the real type in TREE_LIST dependency node. Build argument list with the real type. (create_jdep_list): Use xmalloc. Removed allocation error message. (obtain_incomplete_type): Fixed leading comment. Broadened incoming argument meaning. (register_incomplete_type): Use xmalloc. Removed allocation error message. (safe_layout_class): Fixed leading comment. (jdep_resolve_class): Reversed if statement condition and switch if and else bodies. (resolve_and_layout): Fixed leading comment. Broadened incoming argument meaning. (complete_class_report_errors): New local variable name, for clarity. purify_type_name used for all error cases. (java_get_real_method_name): Stricter check on constructors. (java_check_regular_methods): Reverse methods list only if not already laid out. Layout artificial constructor. (java_check_methods): Deleted. (source_start_java_method): Obtain incomplete type for patchable method arguments. (java_layout_classes): Fixed leading comment. Use LAYOUT_SEEN_CLASS_METHODS, use a loop to check methods. Added else statement to layout operation, reuse LAYOUT_SEEN_CLASS_METHODS before returning. Fixed comments. (java_expand_classes): Check for errors up front. (patch_method_invocation): Class to search is resolved and laid out. A step forward truly mixing .class and .java during package compilation. Includes a Per's patch. From-SVN: r23834 --- gcc/java/ChangeLog | 69 ++++++++ gcc/java/class.c | 373 +++++++++++++++++++++++++------------------ gcc/java/expr.c | 2 + gcc/java/java-tree.h | 12 ++ gcc/java/jcf-parse.c | 49 ++++-- gcc/java/jcf-write.c | 3 +- gcc/java/lang.c | 7 +- gcc/java/lex.c | 8 +- gcc/java/parse.c | 226 ++++++++++++++++---------- gcc/java/parse.h | 43 ++--- gcc/java/parse.y | 219 +++++++++++++++---------- 11 files changed, 649 insertions(+), 362 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 5e039df3de7..a0dd3fb7bab 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,72 @@ +Tue Nov 24 17:06:38 1998 Per Bothner + + * (generate_classfile): Always write class access flag with + ACC_SUPER set. + +Tue Nov 24 16:34:33 1998 Alexandre Petit-Bianco + + * class.c (maybe_layout_super_class): New function. + (layout_class): Reorganized. Loop on class methods dispatched into + a new function. Call maybe_layout_super_class. + (layout_class_methods, layout_class_method): New functions. + * expr.c (expand_java_NEW): Call layout_class_methods on loaded + class. + (expand_invoke): Likewise. + * java-tree.h (all_class_list): New global variable declared. + (layout_class_methods, layout_class_method): New function + prototypes. + (LAYOUT_SEEN_CLASS_METHODS): New macro. + * jcf-parse.c (all_class_list): New global variable. + (load_class): Extended what class_or_name can be. Use parser + context mechanism to save globals before calling jcf_parse. + (jcf_parse_source): Don't parse twice if HAS_BEEN_ALREADY_PARSED_P + is set on the file name. + (jcf_parse): Layout class methods when Object is loaded, otherwise + record class in all_class_list for delayed method layout. + (parse_class_file): Use LAYOUT_SEEN_CLASS_METHODS. + * lang.c (put_decl_node): Decode into the decl context + class name. + * lex.c (java_allocate_new_line): Use xmalloc. + * parse.h (INCOMPLETE_TYPE_P): Redefined to work with incomplete + pointers, not TREE_LIST elements. + (struct parser_ctxt): Fixed comment indentations, added comments + and reordered some fields. + (java_check_methods): Function prototype removed. + * parse.y (java_push_parser_context): Use xmalloc. + (java_parser_context_restore_global): Pop extra pushed ctxp only + when there's nothing next. + (maybe_create_class_interface_decl): Fixed comment, add new + created class decl to all_class_list. + (method_header): Use GET_REAL_TYPE on argument's types. + (method_declarator): Use GET_REAL_TYPE, change type to the real + type in TREE_LIST dependency node. Build argument list with the + real type. + (create_jdep_list): Use xmalloc. Removed allocation error message. + (obtain_incomplete_type): Fixed leading comment. Broadened + incoming argument meaning. + (register_incomplete_type): Use xmalloc. Removed allocation error + message. + (safe_layout_class): Fixed leading comment. + (jdep_resolve_class): Reversed if statement condition and switch + if and else bodies. + (resolve_and_layout): Fixed leading comment. Broadened incoming + argument meaning. + (complete_class_report_errors): New local variable name, for + clarity. purify_type_name used for all error cases. + (java_get_real_method_name): Stricter check on constructors. + (java_check_regular_methods): Reverse methods list only if not + already laid out. Layout artificial constructor. + (java_check_methods): Deleted. + (source_start_java_method): Obtain incomplete type for patchable + method arguments. + (java_layout_classes): Fixed leading comment. Use + LAYOUT_SEEN_CLASS_METHODS, use a loop to check methods. Added else + statement to layout operation, reuse LAYOUT_SEEN_CLASS_METHODS + before returning. Fixed comments. + (java_expand_classes): Check for errors up front. + (patch_method_invocation): Class to search is resolved and laid + out. + Tue Nov 24 12:57:13 1998 Per Bothner * expr.c (java_lang_expand_expr): Add missing emit_queue. diff --git a/gcc/java/class.c b/gcc/java/class.c index 0f8d488d1db..e0ea241c763 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -1323,39 +1323,55 @@ push_super_field (this_class, super_class) DECL_SIZE (base_decl) = TYPE_SIZE (super_class); } +/* Handle the different manners we may have to lay out a super class. */ + +static tree +maybe_layout_super_class (super_class) + tree super_class; +{ + if (TREE_CODE (super_class) == RECORD_TYPE) + { + if (!CLASS_LOADED_P (super_class) + && CLASS_FROM_SOURCE_P (super_class)) + safe_layout_class (super_class); + if (!CLASS_LOADED_P (super_class)) + load_class (super_class, 1); + } + /* We might have to layout the class before its dependency on + the super class gets resolved by java_complete_class */ + else if (TREE_CODE (super_class) == TREE_LIST) + { + tree name = TYPE_NAME (TREE_PURPOSE (super_class)); + load_class (name, 1); + super_class = IDENTIFIER_CLASS_VALUE (name); + if (!super_class) + return; + super_class = TREE_TYPE (super_class); + } + if (!TYPE_SIZE (super_class)) + safe_layout_class (super_class); + + return super_class; +} + void layout_class (this_class) tree this_class; { tree super_class = CLASSTYPE_SUPER (this_class); - tree handle_type = CLASS_TO_HANDLE_TYPE (this_class); - tree method_decl, field; - tree dtable_count; - int i; + tree field; if (super_class) { - /* Class seen in source are now complete and can be layed out. - Once layed out, a class seen in the source has its - CLASS_LOADED_P flag set */ - if (CLASS_FROM_SOURCE_P (super_class) && !CLASS_LOADED_P (super_class)) - safe_layout_class (super_class); - if (! CLASS_LOADED_P (super_class)) - load_class (super_class, 1); + super_class = maybe_layout_super_class (super_class); if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK) { TYPE_SIZE (this_class) = error_mark_node; return; } - dtable_count = TYPE_NVIRTUALS (super_class); - if (TYPE_SIZE (this_class) == NULL_TREE) push_super_field (this_class, super_class); } - else - { - dtable_count = integer_zero_node; - } for (field = TYPE_FIELDS (this_class); field != NULL_TREE; field = TREE_CHAIN (field)) @@ -1368,178 +1384,217 @@ layout_class (this_class) } layout_type (this_class); +} - TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); +void +layout_class_methods (this_class) + tree this_class; +{ + tree method_decl, dtable_count; + tree super_class, handle_type; + + if (TYPE_NVIRTUALS (this_class)) + return; + + push_obstacks (&permanent_obstack, &permanent_obstack); + super_class = CLASSTYPE_SUPER (this_class); + handle_type = CLASS_TO_HANDLE_TYPE (this_class); - for (method_decl = TYPE_METHODS (handle_type), i = 0; - method_decl; method_decl = TREE_CHAIN (method_decl), i++) + if (super_class) { - char *ptr; - char buf[8]; - char *asm_name; - tree method_name = DECL_NAME (method_decl); - int method_name_is_wfl = - (TREE_CODE (method_name) == EXPR_WITH_FILE_LOCATION); - if (method_name_is_wfl) - method_name = java_get_real_method_name (method_decl); + super_class = maybe_layout_super_class (super_class); + if (!TYPE_NVIRTUALS (super_class)) + layout_class_methods (super_class); + dtable_count = TYPE_NVIRTUALS (super_class); + } + else + dtable_count = integer_zero_node; + + TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); + + for (method_decl = TYPE_METHODS (handle_type); + method_decl; method_decl = TREE_CHAIN (method_decl)) + dtable_count = layout_class_method (this_class, super_class, + method_decl, dtable_count); + + TYPE_NVIRTUALS (this_class) = dtable_count; + +#ifdef JAVA_USE_HANDLES + layout_type (handle_type); +#endif + pop_obstacks (); +} + +/* Lay METHOD_DECL out, returning a possibly new value of + DTABLE_COUNT. */ + +tree +layout_class_method (this_class, super_class, method_decl, dtable_count) + tree this_class, super_class, method_decl, dtable_count; +{ + char *ptr; + char buf[8]; + char *asm_name; + tree method_name = DECL_NAME (method_decl); + int method_name_is_wfl = + (TREE_CODE (method_name) == EXPR_WITH_FILE_LOCATION); + if (method_name_is_wfl) + method_name = java_get_real_method_name (method_decl); #if 1 - /* Remove this once we no longer need old (Kaffe / JDK 1.0) mangling. */ - if (! flag_assume_compiled && METHOD_NATIVE (method_decl)) + /* Remove this once we no longer need old (Kaffe / JDK 1.0) mangling. */ + if (! flag_assume_compiled && METHOD_NATIVE (method_decl)) + { + for (ptr = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + *ptr; ) + { + int ch = *ptr++; + if (ch == '.') + ch = '_'; + obstack_1grow (&temporary_obstack, (char) ch); + } + obstack_1grow (&temporary_obstack, (char) '_'); + if (method_name == init_identifier_node) + obstack_grow (&temporary_obstack, "INIT", 4); + else + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } + else +#endif + { + int len; tree arg, arglist, t; + int method_name_needs_escapes = 0; + if (method_name != init_identifier_node + && method_name != finit_identifier_node) { - for (ptr = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); - *ptr; ) + int encoded_len + = unicode_mangling_length (IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + if (encoded_len > 0) { - int ch = *ptr++; - if (ch == '.') - ch = '_'; - obstack_1grow (&temporary_obstack, (char) ch); + method_name_needs_escapes = 1; + emit_unicode_mangled_name (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); } - obstack_1grow (&temporary_obstack, (char) '_'); - if (method_name == init_identifier_node) - obstack_grow (&temporary_obstack, "INIT", 4); else - obstack_grow (&temporary_obstack, - IDENTIFIER_POINTER (method_name), - IDENTIFIER_LENGTH (method_name)); + { + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } } - else -#endif + + obstack_grow (&temporary_obstack, "__", 2); + if (method_name == finit_identifier_node) + obstack_grow (&temporary_obstack, "finit", 5); + append_gpp_mangled_type (&temporary_obstack, this_class); + TREE_PUBLIC (method_decl) = 1; + + t = TREE_TYPE (method_decl); + arglist = TYPE_ARG_TYPES (t); + if (TREE_CODE (t) == METHOD_TYPE) + arglist = TREE_CHAIN (arglist); + for (arg = arglist; arg != NULL_TREE; ) { - int len; tree arg, arglist, t; - int method_name_needs_escapes = 0; - if (method_name != init_identifier_node - && method_name != finit_identifier_node) + tree a = arglist; + tree argtype = TREE_VALUE (arg); + int tindex = 1; + if (TREE_CODE (argtype) == POINTER_TYPE) { - int encoded_len - = unicode_mangling_length (IDENTIFIER_POINTER (method_name), - IDENTIFIER_LENGTH (method_name)); - if (encoded_len > 0) - { - method_name_needs_escapes = 1; - emit_unicode_mangled_name (&temporary_obstack, - IDENTIFIER_POINTER (method_name), - IDENTIFIER_LENGTH (method_name)); - } - else - { - obstack_grow (&temporary_obstack, - IDENTIFIER_POINTER (method_name), - IDENTIFIER_LENGTH (method_name)); - } + /* This is O(N**2). Do we care? Cfr gcc/cp/method.c. */ + while (a != arg && argtype != TREE_VALUE (a)) + a = TREE_CHAIN (a), tindex++; } - - obstack_grow (&temporary_obstack, "__", 2); - if (method_name == finit_identifier_node) - obstack_grow (&temporary_obstack, "finit", 5); - append_gpp_mangled_type (&temporary_obstack, this_class); - TREE_PUBLIC (method_decl) = 1; - - t = TREE_TYPE (method_decl); - arglist = TYPE_ARG_TYPES (t); - if (TREE_CODE (t) == METHOD_TYPE) - arglist = TREE_CHAIN (arglist); - for (arg = arglist; arg != NULL_TREE; ) + else + a = arg; + if (a != arg) { - tree a = arglist; - tree argtype = TREE_VALUE (arg); - int tindex = 1; - if (TREE_CODE (argtype) == POINTER_TYPE) + char buf[12]; + int nrepeats = 0; + do { - /* This is O(N**2). Do we care? Cfr gcc/cp/method.c. */ - while (a != arg && argtype != TREE_VALUE (a)) - a = TREE_CHAIN (a), tindex++; + arg = TREE_CHAIN (arg); nrepeats++; } - else - a = arg; - if (a != arg) + while (arg != NULL_TREE && argtype == TREE_VALUE (arg)); + if (nrepeats > 1) { - char buf[12]; - int nrepeats = 0; - do - { - arg = TREE_CHAIN (arg); nrepeats++; - } - while (arg != NULL_TREE && argtype == TREE_VALUE (arg)); - if (nrepeats > 1) - { - obstack_1grow (&temporary_obstack, 'N'); - sprintf (buf, "%d", nrepeats); - obstack_grow (&temporary_obstack, buf, strlen (buf)); - if (nrepeats > 9) - obstack_1grow (&temporary_obstack, '_'); - } - else - obstack_1grow (&temporary_obstack, 'T'); - sprintf (buf, "%d", tindex); + obstack_1grow (&temporary_obstack, 'N'); + sprintf (buf, "%d", nrepeats); obstack_grow (&temporary_obstack, buf, strlen (buf)); - if (tindex > 9) + if (nrepeats > 9) obstack_1grow (&temporary_obstack, '_'); } else - { - append_gpp_mangled_type (&temporary_obstack, argtype); - arg = TREE_CHAIN (arg); - } + obstack_1grow (&temporary_obstack, 'T'); + sprintf (buf, "%d", tindex); + obstack_grow (&temporary_obstack, buf, strlen (buf)); + if (tindex > 9) + obstack_1grow (&temporary_obstack, '_'); } - if (method_name_needs_escapes) - obstack_1grow (&temporary_obstack, 'U'); - } - obstack_1grow (&temporary_obstack, '\0'); - asm_name = obstack_finish (&temporary_obstack); - DECL_ASSEMBLER_NAME (method_decl) = get_identifier (asm_name); - if (! METHOD_ABSTRACT (method_decl)) - make_function_rtl (method_decl); - obstack_free (&temporary_obstack, asm_name); - - if (method_name == init_identifier_node) - { - char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); - for (ptr = p; *ptr; ) + else { - if (*ptr++ == '.') - p = ptr; + append_gpp_mangled_type (&temporary_obstack, argtype); + arg = TREE_CHAIN (arg); } - if (method_name_is_wfl) - EXPR_WFL_NODE (DECL_NAME (method_decl)) = get_identifier (p); - else - DECL_NAME (method_decl) = get_identifier (p); - DECL_CONSTRUCTOR_P (method_decl) = 1; } - else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl)) + if (method_name_needs_escapes) + obstack_1grow (&temporary_obstack, 'U'); + } + obstack_1grow (&temporary_obstack, '\0'); + asm_name = obstack_finish (&temporary_obstack); + DECL_ASSEMBLER_NAME (method_decl) = get_identifier (asm_name); + if (! METHOD_ABSTRACT (method_decl)) + make_function_rtl (method_decl); + obstack_free (&temporary_obstack, asm_name); + + if (method_name == init_identifier_node) + { + char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + for (ptr = p; *ptr; ) { - tree method_sig = build_java_argument_signature (TREE_TYPE (method_decl)); - tree super_method = lookup_argument_method (super_class, method_name, + if (*ptr++ == '.') + p = ptr; + } + if (method_name_is_wfl) + EXPR_WFL_NODE (DECL_NAME (method_decl)) = get_identifier (p); + else + DECL_NAME (method_decl) = get_identifier (p); + DECL_CONSTRUCTOR_P (method_decl) = 1; + } + else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl)) + { + tree method_sig = + build_java_argument_signature (TREE_TYPE (method_decl)); + tree super_method = lookup_argument_method (super_class, method_name, method_sig); - if (super_method != NULL_TREE) - { - DECL_VINDEX (method_decl) = DECL_VINDEX (super_method); - if (DECL_VINDEX (method_decl) == NULL_TREE) - error_with_decl (method_decl, - "non-static method '%s' overrides static method"); + if (super_method != NULL_TREE) + { + DECL_VINDEX (method_decl) = DECL_VINDEX (super_method); + if (DECL_VINDEX (method_decl) == NULL_TREE) + error_with_decl (method_decl, + "non-static method '%s' overrides static method"); #if 0 - else if (TREE_TYPE (TREE_TYPE (method_decl)) - != TREE_TYPE (TREE_TYPE (super_method))) - { - error_with_decl (method_decl, - "Method `%s' redefined with different return type"); - error_with_decl (super_method, - "Overridden decl is here"); - } +else if (TREE_TYPE (TREE_TYPE (method_decl)) + != TREE_TYPE (TREE_TYPE (super_method))) + { + error_with_decl (method_decl, + "Method `%s' redefined with different return type"); + error_with_decl (super_method, + "Overridden decl is here"); + } #endif - } - else if (! METHOD_FINAL (method_decl) - && ! CLASS_FINAL (TYPE_NAME (this_class))) - { - DECL_VINDEX (method_decl) = dtable_count; - dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0); - } + } + else if (! METHOD_FINAL (method_decl) + && ! CLASS_FINAL (TYPE_NAME (this_class)) + && dtable_count) + { + DECL_VINDEX (method_decl) = dtable_count; + dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0); } } - TYPE_NVIRTUALS (this_class) = dtable_count; - -#ifdef JAVA_USE_HANDLES - layout_type (handle_type); -#endif + return dtable_count; } static tree registered_class = NULL_TREE; diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 5631656ca90..7ac3d19c7ec 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -910,6 +910,7 @@ expand_java_NEW (type) { if (! CLASS_LOADED_P (type)) load_class (type, 1); + layout_class_methods (type); push_value (build (CALL_EXPR, promote_type (type), build_address_of (alloc_object_node), tree_cons (NULL_TREE, build_class_ref (type), @@ -1485,6 +1486,7 @@ expand_invoke (opcode, method_ref_index, nargs) if (TREE_CODE (TYPE_SIZE (self_type)) == ERROR_MARK) fatal ("failed to find class '%s'", self_name); } + layout_class_methods (self_type); if (method_name == init_identifier_node) method = lookup_java_constructor (CLASS_TO_HANDLE_TYPE (self_type), diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 4554638b92a..66aae185e08 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -112,6 +112,9 @@ extern tree main_class; /* The class we are currently processing. */ extern tree current_class; +/* List of all class DECLs seen so far. */ +extern tree all_class_list; + /* Nonzero if we want to automatically do array bounds checking; on by default. Use -fno-bounds-check to disable. */ @@ -483,6 +486,8 @@ extern tree unmangle_classname PROTO ((const char *name, int name_length)); extern tree parse_signature_string PROTO ((const unsigned char *, int)); extern tree get_type_from_signature PROTO ((tree)); extern void layout_class PROTO ((tree)); +extern tree layout_class_method PROTO ((tree, tree, tree, tree)); +extern void layout_class_methods PROTO ((tree)); extern tree make_class (); extern tree build_class_ref PROTO ((tree)); extern tree build_dtable_decl PROTO ((tree)); @@ -835,3 +840,10 @@ extern tree *type_map; if (java_error_count) \ return; \ } + +#define LAYOUT_SEEN_CLASS_METHODS() \ + { \ + tree current; \ + for (current = all_class_list; current; current = TREE_CHAIN (current)) \ + layout_class_methods (TREE_TYPE (TREE_VALUE (current))); \ + } diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 8a01b2cb925..c9f2ed7f5aa 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -61,7 +61,10 @@ tree current_class = NULL_TREE; /* The class we started with. */ tree main_class = NULL_TREE; -/* The FIELD_DECL for the current field. */ +/* List of all class DECL seen so far. */ +tree all_class_list = NULL_TREE; + +/* The FIELD_DECL for the current field. */ static tree current_field = NULL_TREE; /* The METHOD_DECL for the current method. */ @@ -450,8 +453,7 @@ load_class (class_or_name, verbose) int verbose; { JCF this_jcf, *jcf; - tree name = (TREE_CODE (class_or_name) == IDENTIFIER_NODE ? - class_or_name : DECL_NAME (TYPE_NAME (class_or_name))); + tree name; tree save_current_class = current_class; char *save_input_filename = input_filename; JCF *save_current_jcf = current_jcf; @@ -459,6 +461,17 @@ load_class (class_or_name, verbose) if (current_jcf->read_state) saved_pos = ftell (current_jcf->read_state); + /* class_or_name can be the name of the class we want to load */ + if (TREE_CODE (class_or_name) == IDENTIFIER_NODE) + name = class_or_name; + /* In some cases, it's a dependency that we process earlier that + we though */ + else if (TREE_CODE (class_or_name) == TREE_LIST) + name = TYPE_NAME (TREE_PURPOSE (class_or_name)); + /* Or it's a type in the making */ + else + name = DECL_NAME (TYPE_NAME (class_or_name)); + push_obstacks (&permanent_obstack, &permanent_obstack); /* Search in current zip first. */ @@ -494,10 +507,12 @@ load_class (class_or_name, verbose) if (current_jcf->java_source) jcf_parse_source (current_jcf); else { - int saved_lineno = lineno; + java_parser_context_save_global (); + java_push_parser_context (); input_filename = current_jcf->filename; jcf_parse (current_jcf); - lineno = saved_lineno; + java_pop_parser_context (0); + java_parser_context_restore_global (); } if (!current_jcf->seen_in_zip) @@ -524,13 +539,16 @@ jcf_parse_source (jcf) java_push_parser_context (); input_filename = current_jcf->filename; file = get_identifier (input_filename); - if (!(finput = fopen (input_filename, "r"))) - fatal ("input file `%s' just disappeared - jcf_parse_source", - input_filename); - parse_source_file (file); - if (fclose (finput)) - fatal ("can't close input file `%s' stream - jcf_parse_source", - input_filename); + if (!HAS_BEEN_ALREADY_PARSED_P (file)) + { + if (!(finput = fopen (input_filename, "r"))) + fatal ("input file `%s' just disappeared - jcf_parse_source", + input_filename); + parse_source_file (file); + if (fclose (finput)) + fatal ("can't close input file `%s' stream - jcf_parse_source", + input_filename); + } java_pop_parser_context (IS_A_COMMAND_LINE_FILENAME_P (file)); java_parser_context_restore_global (); } @@ -586,6 +604,11 @@ jcf_parse (jcf) push_obstacks (&permanent_obstack, &permanent_obstack); layout_class (current_class); + if (current_class == object_type_node) + layout_class_methods (object_type_node); + else + all_class_list = tree_cons (NULL_TREE, + TYPE_NAME (current_class), all_class_list ); pop_obstacks (); } @@ -612,6 +635,8 @@ parse_class_file () char *save_input_filename = input_filename; int save_lineno = lineno; + LAYOUT_SEEN_CLASS_METHODS (); + input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class)); lineno = 0; debug_start_source_file (input_filename); diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index c371096bd1b..036f4deaa3b 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -2342,7 +2342,8 @@ generate_classfile (clas, state) else i = 8 + 2 * total_supers; ptr = append_chunk (NULL, i, state); - i = get_access_flags (TYPE_NAME (clas)); PUT2 (i); /* acces_flags */ + i = get_access_flags (TYPE_NAME (clas)) | ACC_SUPER; + PUT2 (i); /* acces_flags */ i = find_class_constant (&state->cpool, clas); PUT2 (i); /* this_class */ if (clas == object_type_node) { diff --git a/gcc/java/lang.c b/gcc/java/lang.c index d560550283e..4e646d24a37 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -358,7 +358,12 @@ put_decl_node (node) put_decl_string (".", 1); } #endif - put_decl_node (DECL_NAME (node)); + if (TREE_CODE (node) == FUNCTION_DECL + && DECL_NAME (node) == init_identifier_node + && !DECL_ARTIFICIAL (node) && current_class) + put_decl_node (TYPE_NAME (current_class)); + else + put_decl_node (DECL_NAME (node)); if (TREE_CODE (node) == FUNCTION_DECL && TREE_TYPE (node) != NULL_TREE) { int i = 0; diff --git a/gcc/java/lex.c b/gcc/java/lex.c index 0a632f1bb54..946e5740ca8 100644 --- a/gcc/java/lex.c +++ b/gcc/java/lex.c @@ -153,12 +153,12 @@ java_allocate_new_line () if (!ctxp->c_line) { - ctxp->c_line = (struct java_line *)malloc (sizeof (struct java_line)); + ctxp->c_line = (struct java_line *)xmalloc (sizeof (struct java_line)); ctxp->c_line->max = JAVA_LINE_MAX; - ctxp->c_line->line = (unicode_t *)malloc - (sizeof (unicode_t)*ctxp->c_line->max); + ctxp->c_line->line = (unicode_t *)xmalloc + (sizeof (unicode_t)*ctxp->c_line->max); ctxp->c_line->unicode_escape_p = - (char *)malloc (sizeof (char)*ctxp->c_line->max); + (char *)xmalloc (sizeof (char)*ctxp->c_line->max); ctxp->c_line->white_space_only = 0; } diff --git a/gcc/java/parse.c b/gcc/java/parse.c index 5bee4f3b931..8e147cd85d4 100644 --- a/gcc/java/parse.c +++ b/gcc/java/parse.c @@ -4675,7 +4675,7 @@ void java_push_parser_context () { struct parser_ctxt *new = - (struct parser_ctxt *)malloc(sizeof (struct parser_ctxt)); + (struct parser_ctxt *)xmalloc(sizeof (struct parser_ctxt)); bzero (new, sizeof (struct parser_ctxt)); new->next = ctxp; @@ -4716,7 +4716,7 @@ java_parser_context_restore_global () current_class = ctxp->current_class; input_filename = ctxp->filename; current_function_decl = ctxp->current_function_decl; - if (extra_ctxp_pushed_p) + if (!ctxp->next && extra_ctxp_pushed_p) { java_pop_parser_context (0); extra_ctxp_pushed_p = 0; @@ -5175,8 +5175,9 @@ maybe_create_class_interface_decl (decl, qualified_name, cl) TREE_CHAIN (decl) = ctxp->class_list; ctxp->class_list = decl; - /* Create a new node in the global list */ + /* Create a new nodes in the global lists */ ctxp->gclass_list = tree_cons (NULL_TREE, decl, ctxp->gclass_list); + all_class_list = tree_cons (NULL_TREE, decl, all_class_list); /* Install a new dependency list element */ create_jdep_list (ctxp); @@ -5310,7 +5311,7 @@ create_class (flags, id, super, interfaces) super_decl_type = TREE_TYPE (super_decl); } else - super_decl_type = + super_decl_type = register_incomplete_type (JDEP_SUPER, super, decl, NULL_TREE); } else if (TREE_TYPE (decl) != object_type_node) @@ -5689,8 +5690,7 @@ method_header (flags, type, mdecl, throws) tree itype; patch_stage = JDEP_METHOD_RETURN; itype = register_incomplete_type (patch_stage, type, id, NULL_TREE); - TREE_TYPE (meth) = (TREE_CODE (itype) == TREE_LIST ? - TREE_PURPOSE (itype) : itype); + TREE_TYPE (meth) = GET_REAL_TYPE (itype); } } else @@ -5928,6 +5928,7 @@ method_declarator (id, list) tree name = EXPR_WFL_NODE (wfl_name); tree already, arg_node; tree type_wfl = NULL_TREE; + tree real_type; /* Obtain a suitable type for resolution, if necessary */ SET_TYPE_FOR_RESOLUTION (type, type_wfl, must_chain); @@ -5936,8 +5937,13 @@ method_declarator (id, list) type = build_array_from_name (type, type_wfl, name, &name); EXPR_WFL_NODE (wfl_name) = name; - if (TREE_CODE (type) == RECORD_TYPE) - type = promote_type (type); + real_type = GET_REAL_TYPE (type); + if (TREE_CODE (real_type) == RECORD_TYPE) + { + real_type = promote_type (real_type); + if (TREE_CODE (type) == TREE_LIST) + TREE_PURPOSE (type) = real_type; + } /* Check redefinition */ for (already = arg_types; already; already = TREE_CHAIN (already)) @@ -5963,7 +5969,7 @@ method_declarator (id, list) } /* The argument node: a name and a (possibly) incomplete type */ - arg_node = build_tree_list (name, type); + arg_node = build_tree_list (name, real_type); if (jdep) JDEP_GET_PATCH (jdep) = &TREE_VALUE (arg_node); TREE_CHAIN (arg_node) = arg_types; @@ -6081,11 +6087,7 @@ static void create_jdep_list (ctxp) struct parser_ctxt *ctxp; { - jdeplist *new = malloc (sizeof (jdeplist)); - - if (!new) - fatal ("Can't alloc jdeplist - create_jdep_list"); - + jdeplist *new = (jdeplist *)xmalloc (sizeof (jdeplist)); new->first = new->last = NULL; new->next = ctxp->classd_list; ctxp->classd_list = new; @@ -6105,14 +6107,22 @@ reverse_jdep_list (ctxp) return prev; } -/* Create a fake pointer based on the ID stored in the WFL */ +/* Create a fake pointer based on the ID stored in + TYPE_NAME. TYPE_NAME can be a WFL or a incomplete type asking to be + registered again. */ static tree -obtain_incomplete_type (wfl) - tree wfl; +obtain_incomplete_type (type_name) + tree type_name; { - tree ptr; - tree name = EXPR_WFL_NODE (wfl); + tree ptr, name; + + if (TREE_CODE (type_name) == EXPR_WITH_FILE_LOCATION) + name = EXPR_WFL_NODE (type_name); + else if (INCOMPLETE_TYPE_P (type_name)) + name = TYPE_NAME (type_name); + else + fatal ("invalid type name - obtain_incomplete_type"); for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr)) if (TYPE_NAME (TREE_PURPOSE (ptr)) == name) @@ -6143,10 +6153,8 @@ register_incomplete_type (kind, wfl, decl, ptr) int kind; tree wfl, decl, ptr; { - jdep *new = malloc (sizeof (jdep)); + jdep *new = (jdep *)xmalloc (sizeof (jdep)); - if (!new) - fatal ("Can't allocate new jdep - register_incomplete_type"); if (!ptr && kind != JDEP_METHOD_END) /* JDEP_METHOD_END is a mere marker */ ptr = obtain_incomplete_type (wfl); @@ -6195,6 +6203,10 @@ java_check_circular_reference () } } +/* safe_layout_class just makes sure that we can load a class without + disrupting the current_class, input_file, lineno, etc, information + about the class processed currently. */ + void safe_layout_class (class) tree class; @@ -6220,20 +6232,18 @@ jdep_resolve_class (dep) { tree decl; - if (!JDEP_RESOLVED_P (dep)) + if (JDEP_RESOLVED_P (dep)) + decl = JDEP_RESOLVED_DECL (dep); + else { - decl = - resolve_class (JDEP_TO_RESOLVE (dep), JDEP_DECL (dep), JDEP_WFL (dep)); + decl = resolve_class (JDEP_TO_RESOLVE (dep), + JDEP_DECL (dep), JDEP_WFL (dep)); JDEP_RESOLVED (dep, decl); } - else - decl = JDEP_RESOLVED_DECL (dep); - + if (!decl) - { - complete_class_report_errors (dep); - return NULL_TREE; - } + complete_class_report_errors (dep); + return decl; } @@ -6486,7 +6496,8 @@ do_resolve_class (class_type, decl, cl) } /* Resolve NAME and lay it out (if not done and if not the current - parsed class). Return a decl node. */ + parsed class). Return a decl node. This function is meant to be + called when type resolution is necessary during the walk pass. */ static tree resolve_and_layout (something, cl) @@ -6495,20 +6506,49 @@ resolve_and_layout (something, cl) { tree decl; - if (TREE_CODE (something) == POINTER_TYPE) - something = TREE_TYPE (something); + /* Don't do that on the current class */ + if (something == current_class) + return TYPE_NAME (current_class); + /* Don't do anything for void and other primitive types */ if (JPRIMITIVE_TYPE_P (something) || something == void_type_node) return NULL_TREE; + /* Pointer types can be reall pointer types or fake pointers. When + finding a real pointer, recheck for primitive types */ + if (TREE_CODE (something) == POINTER_TYPE) + { + if (TREE_TYPE (something)) + { + something = TREE_TYPE (something); + if (JPRIMITIVE_TYPE_P (something) || something == void_type_node) + return NULL_TREE; + } + else + something = TYPE_NAME (something); + } + + /* Don't do anything for arrays of primitive types */ + if (TREE_CODE (something) == RECORD_TYPE && TYPE_ARRAY_P (something) + && JPRIMITIVE_TYPE_P (TYPE_ARRAY_ELEMENT (something))) + return NULL_TREE; + + /* If something is not and IDENTIFIER_NODE, it can be a a TYPE_DECL + or a real TYPE */ if (TREE_CODE (something) != IDENTIFIER_NODE) something = (TREE_CODE (TYPE_NAME (something)) == TYPE_DECL ? DECL_NAME (TYPE_NAME (something)) : TYPE_NAME (something)); - decl = resolve_no_layout (something, cl); - if (decl && TREE_TYPE (decl) != current_class - && !CLASS_LOADED_P (TREE_TYPE (decl))) + if (!(decl = resolve_no_layout (something, cl))) + return NULL_TREE; + + /* Resolve and layout if necessary */ + layout_class_methods (TREE_TYPE (decl)); + if (CLASS_FROM_SOURCE_P (TREE_TYPE (decl))) + CHECK_METHODS (decl); + if (TREE_TYPE (decl) != current_class && !CLASS_LOADED_P (TREE_TYPE (decl))) safe_layout_class (TREE_TYPE (decl)); + return decl; } @@ -6528,8 +6568,10 @@ resolve_no_layout (name, cl) return decl; } -/* Called to report errors. Skip leader '[' in a complex array type - description that failed to be resolved. */ +/* Called when reporting errors. Skip leader '[' in a complex array + type description that failed to be resolved. Append a matching + number of [] at the end of a newly allocated string that contains + the type's name part. */ static char * purify_type_name (name) @@ -6537,6 +6579,7 @@ purify_type_name (name) { while (*name && *name == '[') name++; + return name; } @@ -6546,25 +6589,31 @@ static void complete_class_report_errors (dep) jdep *dep; { + char *name; + + if (!JDEP_WFL (dep)) + return; + + name = IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))); switch (JDEP_KIND (dep)) { case JDEP_SUPER: parse_error_context (JDEP_WFL (dep), "Superclass `%s' of class `%s' not found", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); break; case JDEP_FIELD: parse_error_context (JDEP_WFL (dep), "Type `%s' not found in declaration of field `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); break; case JDEP_METHOD: /* Covers arguments */ parse_error_context (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " "argument `%s' of method `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_MISC (dep)))); break; @@ -6572,7 +6621,7 @@ complete_class_report_errors (dep) parse_error_context (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " "return type of method `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep)))); break; case JDEP_INTERFACE: @@ -6662,8 +6711,11 @@ java_get_real_method_name (method_decl) tree method_name = DECL_NAME (method_decl); if (DECL_CONSTRUCTOR_P (method_decl)) return init_identifier_node; - else if (ctxp - && ctxp->current_parsed_class_un == EXPR_WFL_NODE (method_name)) + /* Don't confuse method only bearing the name of their class as + constructors */ + else if (ctxp && ctxp->current_parsed_class_un == EXPR_WFL_NODE (method_name) + && get_access_flags_from_decl (method_decl) <= ACC_PROTECTED + && TREE_TYPE (TREE_TYPE (method_decl)) == void_type_node) return init_identifier_node; else return EXPR_WFL_NODE (method_name); @@ -6728,7 +6780,8 @@ java_check_regular_methods (class_decl) if (class == object_type_node) return; - TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + if (!TYPE_NVIRTUALS (class)) + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); /* Should take interfaces into account. FIXME */ for (method = TYPE_METHODS (class); method; method = TREE_CHAIN (method)) @@ -6877,11 +6930,15 @@ java_check_regular_methods (class_decl) if (found && !DECL_ARTIFICIAL (found) && saved_found_wfl) DECL_NAME (found) = saved_found_wfl; - TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + if (!TYPE_NVIRTUALS (class)) + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); if (!saw_constructor) { - /* No constructor seen, we craft one, at line 0 */ + /* No constructor seen, we craft one, at line 0. Since this + operation takes place after we laid methods out + (layout_class_methods), we prepare the its DECL + appropriately. */ int flags; tree decl; @@ -6893,6 +6950,7 @@ java_check_regular_methods (class_decl) decl = create_artificial_method (class, flags, void_type_node, init_identifier_node, NULL_TREE); DECL_CONSTRUCTOR_P (decl) = 1; + layout_class_method (TREE_TYPE (class_decl), NULL_TREE, decl, NULL_TREE); } } @@ -7013,18 +7071,6 @@ java_check_abstract_methods (interface_decl) } } -/* Check the method on all the defined classes. Process all the - classes that we compiled from source code for this CU. */ - -void -java_check_methods () -{ - tree current; - for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) - if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current)))) - CHECK_METHODS (TREE_VALUE (current)); -} - /* Lookup methods in interfaces using their name and partial signature. Return a matching method only if their types differ. */ @@ -7598,14 +7644,14 @@ source_start_java_method (fndecl) tree type = TREE_VALUE (tem); tree name = TREE_PURPOSE (tem); - /* If type is incomplete. Layout can't take place - now. Create an incomplete decl and ask for the decl to be - patched later */ + /* If type is incomplete. Create an incomplete decl and ask for + the decl to be patched later */ if (INCOMPLETE_TYPE_P (type)) { jdep *jdep; tree real_type = GET_REAL_TYPE (type); parm_decl = build_decl (PARM_DECL, name, real_type); + type = obtain_incomplete_type (type); register_incomplete_type (JDEP_PARM, NULL_TREE, NULL_TREE, type); jdep = CLASSD_LAST (ctxp->classd_list); JDEP_MISC (jdep) = name; @@ -7784,18 +7830,27 @@ add_stmt_to_compound (existing, type, stmt) /* Hold THIS for the scope of the current public method decl. */ static tree current_this; -/* Layout all class found during parsing. Also fixes the order of some - lists. */ +/* Layout the methods of all classes loaded in one way on an + other. Check methods of source parsed classes. Then reorder the + fields and layout the classes or the type of all source parsed + classes */ void java_layout_classes () { tree current; - java_check_methods (); - /* Error reported by the caller */ - if (java_error_count) - return; + /* Layout the methods of all classes seen so far */ + LAYOUT_SEEN_CLASS_METHODS (); + java_parse_abort_on_error (); + all_class_list = NULL_TREE; + + /* Then check the methods of all parsed classes */ + for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) + if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current)))) + CHECK_METHODS (TREE_VALUE (current)); + java_parse_abort_on_error (); + for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) { current_class = TREE_TYPE (TREE_VALUE (current)); @@ -7805,8 +7860,8 @@ java_layout_classes () if (TYPE_FIELDS (current_class) && current_class != object_type_node && current_class != class_type_node) { - /* Always leave the dummy field in front if its already there, - and layout the class for proper field offets. */ + /* If the dummy field is there, reverse the right fields and + just layout the type for proper fields offset */ if (!DECL_NAME (TYPE_FIELDS (current_class))) { tree fields = TYPE_FIELDS (current_class); @@ -7814,7 +7869,8 @@ java_layout_classes () TYPE_SIZE (current_class) = NULL_TREE; layout_type (current_class); } - /* It's time to layout the class */ + /* We don't have a dummy field, we need to layout the class, + after having reversed the fields */ else { TYPE_FIELDS (current_class) = @@ -7823,12 +7879,8 @@ java_layout_classes () layout_class (current_class); } } - - /* Do a layout if necessary */ - if (!TYPE_SIZE (current_class) - || (current_class == object_type_node) - || current_class == class_type_node) - safe_layout_class (current_class); + else + layout_class (current_class); /* From now on, the class is considered completely loaded */ CLASS_LOADED_P (current_class) = 1; @@ -7837,6 +7889,12 @@ java_layout_classes () if (java_error_count) return; } + + /* We might have reloaded classes durign the process of laying out + classes for code generation. We must layout the methods of those + late additions, as constructor checks might use them */ + LAYOUT_SEEN_CLASS_METHODS (); + java_parse_abort_on_error (); } /* Expand all methods in all registered classes. */ @@ -8100,9 +8158,8 @@ java_expand_finals () void java_expand_classes () { - ctxp = ctxp_for_generation; - /* If we found error earlier, we don't want to report then twice. */ - if (java_error_count || !ctxp) + java_parse_abort_on_error (); + if (!(ctxp = ctxp_for_generation)) return; java_layout_classes (); java_parse_abort_on_error (); @@ -8996,7 +9053,8 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl, super) /* Class to search is NULL if we're searching the current one */ if (class_to_search) { - class_to_search = resolve_no_layout (class_to_search, NULL_TREE); + class_to_search = resolve_and_layout (class_to_search, + NULL_TREE); if (!class_to_search) { parse_error_context @@ -9817,6 +9875,7 @@ java_complete_tree (node) TREE_OPERAND (node, 0) = cn; TREE_TYPE (node) = void_type_node; CAN_COMPLETE_NORMALLY (node) = 1; + TREE_SIDE_EFFECTS (node) = 1; break; case DEFAULT_EXPR: @@ -9832,6 +9891,7 @@ java_complete_tree (node) else SWITCH_HAS_DEFAULT (nn) = 1; TREE_TYPE (node) = void_type_node; + TREE_SIDE_EFFECTS (node) = 1; CAN_COMPLETE_NORMALLY (node) = 1; break; diff --git a/gcc/java/parse.h b/gcc/java/parse.h index b2b06445789..b73b8db1dc4 100644 --- a/gcc/java/parse.h +++ b/gcc/java/parse.h @@ -147,10 +147,10 @@ extern tree stabilize_reference PROTO ((tree)); TYPE_NAME (ptr) = name; \ } -#define INCOMPLETE_TYPE_P(NODE) \ - ((TREE_CODE (NODE) == TREE_LIST) \ - && (TREE_CODE (TREE_PURPOSE (NODE)) == POINTER_TYPE) \ - && (TREE_TYPE (TREE_PURPOSE (NODE)) == NULL_TREE)) +#define INCOMPLETE_TYPE_P(NODE) \ + ((TREE_CODE (NODE) == POINTER_TYPE) \ + && !TREE_TYPE (NODE) \ + && TREE_CODE (TYPE_NAME (NODE)) == IDENTIFIER_NODE) /* Set the EMIT_LINE_NOTE flag of a EXPR_WLF to 1 if debug information are requested. Works in the context of a parser rule. */ @@ -589,13 +589,13 @@ struct parser_ctxt { int parser_ccb_indent; /* Keep track of {} indent, parser */ int osb_number; /* Keep track of ['s */ int minus_seen; /* Integral literal overflow */ - int lineno; /* Current lineno */ - int java_error_flag; /* Report error when true */ + int lineno; /* Current lineno */ + int java_error_flag; /* Report error when true */ int deprecated; /* @deprecated tag seen */ /* This section is defined only if we compile jc1 */ #ifndef JC1_LITE - tree modifier_ctx [11]; /* WFL of modifiers */ + tree modifier_ctx [11]; /* WFL of modifiers */ tree current_class; /* Current class */ tree current_function_decl; /* Current function decl, save/restore */ @@ -609,30 +609,34 @@ struct parser_ctxt { tree package; /* Defined package ID */ + /* Those tow list are saved accross file traversal */ tree incomplete_class; /* List of non-complete classes */ - tree current_parsed_class; /* Class currently parsed */ - tree current_parsed_class_un; /* Curr. parsed class unqualified name */ + tree gclass_list; /* All classes seen from source code */ + + /* These two lists won't survive file traversal */ tree class_list; /* List of classes in a CU */ - tree gclass_list; /* All classes seen so far. */ jdeplist *classd_list; /* Classe dependencies in a CU */ + tree current_parsed_class; /* Class currently parsed */ + tree current_parsed_class_un; /* Curr. parsed class unqualified name */ + tree non_static_initialized; /* List of non static initialized fields */ tree static_initialized; /* List of static non final initialized */ tree import_list; /* List of import */ tree import_demand_list; /* List of import on demand */ - tree current_loop; /* List of the currently nested loops/switches */ - tree current_labeled_block; /* List of currently nested - labeled blocks. */ + tree current_loop; /* List of the currently nested + loops/switches */ + tree current_labeled_block; /* List of currently nested + labeled blocks. */ - int pending_block; /* Pending block to close */ + int pending_block; /* Pending block to close */ - int explicit_constructor_p; /* True when processing an - explicit constructor. This flag is - used to trap illegal argument usage - during an explicit constructor - invocation. */ + int explicit_constructor_p; /* True when processing an explicit + constructor. This flag is used to trap + illegal argument usage during an + explicit constructor invocation. */ #endif /* JC1_LITE */ }; @@ -803,7 +807,6 @@ void safe_layout_class PROTO ((tree)); void java_complete_class PROTO ((void)); void java_check_circular_reference PROTO ((void)); void java_check_final PROTO ((void)); -void java_check_methods PROTO ((void)); void java_layout_classes PROTO ((void)); tree java_method_add_stmt PROTO ((tree, tree)); char *java_get_line_col PROTO ((char *, int, int)); diff --git a/gcc/java/parse.y b/gcc/java/parse.y index d59210b9870..be09d7256d4 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -2070,7 +2070,7 @@ void java_push_parser_context () { struct parser_ctxt *new = - (struct parser_ctxt *)malloc(sizeof (struct parser_ctxt)); + (struct parser_ctxt *)xmalloc(sizeof (struct parser_ctxt)); bzero (new, sizeof (struct parser_ctxt)); new->next = ctxp; @@ -2111,7 +2111,7 @@ java_parser_context_restore_global () current_class = ctxp->current_class; input_filename = ctxp->filename; current_function_decl = ctxp->current_function_decl; - if (extra_ctxp_pushed_p) + if (!ctxp->next && extra_ctxp_pushed_p) { java_pop_parser_context (0); extra_ctxp_pushed_p = 0; @@ -2570,8 +2570,9 @@ maybe_create_class_interface_decl (decl, qualified_name, cl) TREE_CHAIN (decl) = ctxp->class_list; ctxp->class_list = decl; - /* Create a new node in the global list */ + /* Create a new nodes in the global lists */ ctxp->gclass_list = tree_cons (NULL_TREE, decl, ctxp->gclass_list); + all_class_list = tree_cons (NULL_TREE, decl, all_class_list); /* Install a new dependency list element */ create_jdep_list (ctxp); @@ -3084,8 +3085,7 @@ method_header (flags, type, mdecl, throws) tree itype; patch_stage = JDEP_METHOD_RETURN; itype = register_incomplete_type (patch_stage, type, id, NULL_TREE); - TREE_TYPE (meth) = (TREE_CODE (itype) == TREE_LIST ? - TREE_PURPOSE (itype) : itype); + TREE_TYPE (meth) = GET_REAL_TYPE (itype); } } else @@ -3323,6 +3323,7 @@ method_declarator (id, list) tree name = EXPR_WFL_NODE (wfl_name); tree already, arg_node; tree type_wfl = NULL_TREE; + tree real_type; /* Obtain a suitable type for resolution, if necessary */ SET_TYPE_FOR_RESOLUTION (type, type_wfl, must_chain); @@ -3331,8 +3332,13 @@ method_declarator (id, list) type = build_array_from_name (type, type_wfl, name, &name); EXPR_WFL_NODE (wfl_name) = name; - if (TREE_CODE (type) == RECORD_TYPE) - type = promote_type (type); + real_type = GET_REAL_TYPE (type); + if (TREE_CODE (real_type) == RECORD_TYPE) + { + real_type = promote_type (real_type); + if (TREE_CODE (type) == TREE_LIST) + TREE_PURPOSE (type) = real_type; + } /* Check redefinition */ for (already = arg_types; already; already = TREE_CHAIN (already)) @@ -3358,7 +3364,7 @@ method_declarator (id, list) } /* The argument node: a name and a (possibly) incomplete type */ - arg_node = build_tree_list (name, type); + arg_node = build_tree_list (name, real_type); if (jdep) JDEP_GET_PATCH (jdep) = &TREE_VALUE (arg_node); TREE_CHAIN (arg_node) = arg_types; @@ -3476,11 +3482,7 @@ static void create_jdep_list (ctxp) struct parser_ctxt *ctxp; { - jdeplist *new = malloc (sizeof (jdeplist)); - - if (!new) - fatal ("Can't alloc jdeplist - create_jdep_list"); - + jdeplist *new = (jdeplist *)xmalloc (sizeof (jdeplist)); new->first = new->last = NULL; new->next = ctxp->classd_list; ctxp->classd_list = new; @@ -3500,14 +3502,22 @@ reverse_jdep_list (ctxp) return prev; } -/* Create a fake pointer based on the ID stored in the WFL */ +/* Create a fake pointer based on the ID stored in + TYPE_NAME. TYPE_NAME can be a WFL or a incomplete type asking to be + registered again. */ static tree -obtain_incomplete_type (wfl) - tree wfl; +obtain_incomplete_type (type_name) + tree type_name; { - tree ptr; - tree name = EXPR_WFL_NODE (wfl); + tree ptr, name; + + if (TREE_CODE (type_name) == EXPR_WITH_FILE_LOCATION) + name = EXPR_WFL_NODE (type_name); + else if (INCOMPLETE_TYPE_P (type_name)) + name = TYPE_NAME (type_name); + else + fatal ("invalid type name - obtain_incomplete_type"); for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr)) if (TYPE_NAME (TREE_PURPOSE (ptr)) == name) @@ -3538,10 +3548,8 @@ register_incomplete_type (kind, wfl, decl, ptr) int kind; tree wfl, decl, ptr; { - jdep *new = malloc (sizeof (jdep)); + jdep *new = (jdep *)xmalloc (sizeof (jdep)); - if (!new) - fatal ("Can't allocate new jdep - register_incomplete_type"); if (!ptr && kind != JDEP_METHOD_END) /* JDEP_METHOD_END is a mere marker */ ptr = obtain_incomplete_type (wfl); @@ -3590,6 +3598,10 @@ java_check_circular_reference () } } +/* safe_layout_class just makes sure that we can load a class without + disrupting the current_class, input_file, lineno, etc, information + about the class processed currently. */ + void safe_layout_class (class) tree class; @@ -3615,20 +3627,18 @@ jdep_resolve_class (dep) { tree decl; - if (!JDEP_RESOLVED_P (dep)) + if (JDEP_RESOLVED_P (dep)) + decl = JDEP_RESOLVED_DECL (dep); + else { - decl = - resolve_class (JDEP_TO_RESOLVE (dep), JDEP_DECL (dep), JDEP_WFL (dep)); + decl = resolve_class (JDEP_TO_RESOLVE (dep), + JDEP_DECL (dep), JDEP_WFL (dep)); JDEP_RESOLVED (dep, decl); } - else - decl = JDEP_RESOLVED_DECL (dep); - + if (!decl) - { - complete_class_report_errors (dep); - return NULL_TREE; - } + complete_class_report_errors (dep); + return decl; } @@ -3881,7 +3891,8 @@ do_resolve_class (class_type, decl, cl) } /* Resolve NAME and lay it out (if not done and if not the current - parsed class). Return a decl node. */ + parsed class). Return a decl node. This function is meant to be + called when type resolution is necessary during the walk pass. */ static tree resolve_and_layout (something, cl) @@ -3890,20 +3901,49 @@ resolve_and_layout (something, cl) { tree decl; - if (TREE_CODE (something) == POINTER_TYPE) - something = TREE_TYPE (something); + /* Don't do that on the current class */ + if (something == current_class) + return TYPE_NAME (current_class); + /* Don't do anything for void and other primitive types */ if (JPRIMITIVE_TYPE_P (something) || something == void_type_node) return NULL_TREE; + /* Pointer types can be reall pointer types or fake pointers. When + finding a real pointer, recheck for primitive types */ + if (TREE_CODE (something) == POINTER_TYPE) + { + if (TREE_TYPE (something)) + { + something = TREE_TYPE (something); + if (JPRIMITIVE_TYPE_P (something) || something == void_type_node) + return NULL_TREE; + } + else + something = TYPE_NAME (something); + } + + /* Don't do anything for arrays of primitive types */ + if (TREE_CODE (something) == RECORD_TYPE && TYPE_ARRAY_P (something) + && JPRIMITIVE_TYPE_P (TYPE_ARRAY_ELEMENT (something))) + return NULL_TREE; + + /* If something is not and IDENTIFIER_NODE, it can be a a TYPE_DECL + or a real TYPE */ if (TREE_CODE (something) != IDENTIFIER_NODE) something = (TREE_CODE (TYPE_NAME (something)) == TYPE_DECL ? DECL_NAME (TYPE_NAME (something)) : TYPE_NAME (something)); - decl = resolve_no_layout (something, cl); - if (decl && TREE_TYPE (decl) != current_class - && !CLASS_LOADED_P (TREE_TYPE (decl))) + if (!(decl = resolve_no_layout (something, cl))) + return NULL_TREE; + + /* Resolve and layout if necessary */ + layout_class_methods (TREE_TYPE (decl)); + if (CLASS_FROM_SOURCE_P (TREE_TYPE (decl))) + CHECK_METHODS (decl); + if (TREE_TYPE (decl) != current_class && !CLASS_LOADED_P (TREE_TYPE (decl))) safe_layout_class (TREE_TYPE (decl)); + return decl; } @@ -3923,8 +3963,8 @@ resolve_no_layout (name, cl) return decl; } -/* Called to report errors. Skip leader '[' in a complex array type - description that failed to be resolved. */ +/* Called when reporting errors. Skip leader '[' in a complex array + type description that failed to be resolved. */ static char * purify_type_name (name) @@ -3941,25 +3981,31 @@ static void complete_class_report_errors (dep) jdep *dep; { + char *name; + + if (!JDEP_WFL (dep)) + return; + + name = IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))); switch (JDEP_KIND (dep)) { case JDEP_SUPER: parse_error_context (JDEP_WFL (dep), "Superclass `%s' of class `%s' not found", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); break; case JDEP_FIELD: parse_error_context (JDEP_WFL (dep), "Type `%s' not found in declaration of field `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); break; case JDEP_METHOD: /* Covers arguments */ parse_error_context (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " "argument `%s' of method `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_MISC (dep)))); break; @@ -3967,7 +4013,7 @@ complete_class_report_errors (dep) parse_error_context (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " "return type of method `%s'", - IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + purify_type_name (name), IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep)))); break; case JDEP_INTERFACE: @@ -4057,8 +4103,11 @@ java_get_real_method_name (method_decl) tree method_name = DECL_NAME (method_decl); if (DECL_CONSTRUCTOR_P (method_decl)) return init_identifier_node; - else if (ctxp - && ctxp->current_parsed_class_un == EXPR_WFL_NODE (method_name)) + /* Don't confuse method only bearing the name of their class as + constructors */ + else if (ctxp && ctxp->current_parsed_class_un == EXPR_WFL_NODE (method_name) + && get_access_flags_from_decl (method_decl) <= ACC_PROTECTED + && TREE_TYPE (TREE_TYPE (method_decl)) == void_type_node) return init_identifier_node; else return EXPR_WFL_NODE (method_name); @@ -4123,7 +4172,8 @@ java_check_regular_methods (class_decl) if (class == object_type_node) return; - TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + if (!TYPE_NVIRTUALS (class)) + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); /* Should take interfaces into account. FIXME */ for (method = TYPE_METHODS (class); method; method = TREE_CHAIN (method)) @@ -4272,11 +4322,15 @@ java_check_regular_methods (class_decl) if (found && !DECL_ARTIFICIAL (found) && saved_found_wfl) DECL_NAME (found) = saved_found_wfl; - TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + if (!TYPE_NVIRTUALS (class)) + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); if (!saw_constructor) { - /* No constructor seen, we craft one, at line 0 */ + /* No constructor seen, we craft one, at line 0. Since this + operation takes place after we laid methods out + (layout_class_methods), we prepare the its DECL + appropriately. */ int flags; tree decl; @@ -4288,6 +4342,7 @@ java_check_regular_methods (class_decl) decl = create_artificial_method (class, flags, void_type_node, init_identifier_node, NULL_TREE); DECL_CONSTRUCTOR_P (decl) = 1; + layout_class_method (TREE_TYPE (class_decl), NULL_TREE, decl, NULL_TREE); } } @@ -4408,18 +4463,6 @@ java_check_abstract_methods (interface_decl) } } -/* Check the method on all the defined classes. Process all the - classes that we compiled from source code for this CU. */ - -void -java_check_methods () -{ - tree current; - for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) - if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current)))) - CHECK_METHODS (TREE_VALUE (current)); -} - /* Lookup methods in interfaces using their name and partial signature. Return a matching method only if their types differ. */ @@ -4993,14 +5036,14 @@ source_start_java_method (fndecl) tree type = TREE_VALUE (tem); tree name = TREE_PURPOSE (tem); - /* If type is incomplete. Layout can't take place - now. Create an incomplete decl and ask for the decl to be - patched later */ + /* If type is incomplete. Create an incomplete decl and ask for + the decl to be patched later */ if (INCOMPLETE_TYPE_P (type)) { jdep *jdep; tree real_type = GET_REAL_TYPE (type); parm_decl = build_decl (PARM_DECL, name, real_type); + type = obtain_incomplete_type (type); register_incomplete_type (JDEP_PARM, NULL_TREE, NULL_TREE, type); jdep = CLASSD_LAST (ctxp->classd_list); JDEP_MISC (jdep) = name; @@ -5179,18 +5222,27 @@ add_stmt_to_compound (existing, type, stmt) /* Hold THIS for the scope of the current public method decl. */ static tree current_this; -/* Layout all class found during parsing. Also fixes the order of some - lists. */ +/* Layout the methods of all classes loaded in one way on an + other. Check methods of source parsed classes. Then reorder the + fields and layout the classes or the type of all source parsed + classes */ void java_layout_classes () { tree current; - java_check_methods (); - /* Error reported by the caller */ - if (java_error_count) - return; + /* Layout the methods of all classes seen so far */ + LAYOUT_SEEN_CLASS_METHODS (); + java_parse_abort_on_error (); + all_class_list = NULL_TREE; + + /* Then check the methods of all parsed classes */ + for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) + if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current)))) + CHECK_METHODS (TREE_VALUE (current)); + java_parse_abort_on_error (); + for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current)) { current_class = TREE_TYPE (TREE_VALUE (current)); @@ -5200,8 +5252,8 @@ java_layout_classes () if (TYPE_FIELDS (current_class) && current_class != object_type_node && current_class != class_type_node) { - /* Always leave the dummy field in front if its already there, - and layout the class for proper field offets. */ + /* If the dummy field is there, reverse the right fields and + just layout the type for proper fields offset */ if (!DECL_NAME (TYPE_FIELDS (current_class))) { tree fields = TYPE_FIELDS (current_class); @@ -5209,7 +5261,8 @@ java_layout_classes () TYPE_SIZE (current_class) = NULL_TREE; layout_type (current_class); } - /* It's time to layout the class */ + /* We don't have a dummy field, we need to layout the class, + after having reversed the fields */ else { TYPE_FIELDS (current_class) = @@ -5218,12 +5271,8 @@ java_layout_classes () layout_class (current_class); } } - - /* Do a layout if necessary */ - if (!TYPE_SIZE (current_class) - || (current_class == object_type_node) - || current_class == class_type_node) - safe_layout_class (current_class); + else + layout_class (current_class); /* From now on, the class is considered completely loaded */ CLASS_LOADED_P (current_class) = 1; @@ -5232,6 +5281,12 @@ java_layout_classes () if (java_error_count) return; } + + /* We might have reloaded classes durign the process of laying out + classes for code generation. We must layout the methods of those + late additions, as constructor checks might use them */ + LAYOUT_SEEN_CLASS_METHODS (); + java_parse_abort_on_error (); } /* Expand all methods in all registered classes. */ @@ -5495,9 +5550,8 @@ java_expand_finals () void java_expand_classes () { - ctxp = ctxp_for_generation; - /* If we found error earlier, we don't want to report then twice. */ - if (java_error_count || !ctxp) + java_parse_abort_on_error (); + if (!(ctxp = ctxp_for_generation)) return; java_layout_classes (); java_parse_abort_on_error (); @@ -6391,7 +6445,8 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl, super) /* Class to search is NULL if we're searching the current one */ if (class_to_search) { - class_to_search = resolve_no_layout (class_to_search, NULL_TREE); + class_to_search = resolve_and_layout (class_to_search, + NULL_TREE); if (!class_to_search) { parse_error_context -- 2.30.2