From e164eae76e4e677e729d62cf39e1c51e4ef7f311 Mon Sep 17 00:00:00 2001 From: aph Date: Fri, 24 Oct 2003 09:29:43 +0000 Subject: [PATCH] 2003-10-22 Andrew Haley * lang.c (LANG_HOOKS_GET_CALLEE_FNDECL): New. (java_get_callee_fndecl): New. * jcf-parse.c (java_parse_file): Call emit_catch_table(). * java-tree.h (ctable_decl): New. (catch_classes): New. (java_tree_index): Add JTI_CTABLE_DECL, JTI_CATCH_CLASSES. * decl.c (java_init_decl_processing): Add catch_class_type. Add ctable_decl. Add catch_classes field. * class.c (build_indirect_class_ref): Break out from build_class_ref. (make_field_value): Check flag_indirect_dispatch. (make_class_data): Ditto. Tidy uses of PUSH_FIELD_VALUE. Add field catch_classes. (make_catch_class_record): New. * java-tree.h (PUSH_FIELD_VALUE): Tidy. 2003-10-22 Andrew Haley * java/lang/natClass.cc (initializeClass): Call _Jv_linkExceptionClassTable. (_Jv_LinkSymbolTable): Call )_Jv_ThrowNoSuchMethodError. Call _Jv_Defer_Resolution on a method whose ncode is NULL. (_Jv_linkExceptionClassTable): New function. (_Jv_LayoutVTableMethods): If superclass looks like a constant pool entry, look it up. * java/lang/Class.h (struct _Jv_CatchClass): New. (_Jv_linkExceptionClassTable): New friend. (_Jv_Defer_Resolution): New friend. (class Class.catch_classes): New field. * include/java-interp.h (Jv_Defer_Resolution): New method. (_Jv_PrepareClass): Make a friend of _Jv_MethodBase. (_Jv_MethodBase.deferred): New field. (_Jv_Defer_Resolution): New function. * resolve.cc (_Jv_PrepareClass): Resolve deferred handlers. * exception.cc (get_ttype_entry): Change return type to void**. (PERSONALITY_FUNCTION): Remove all code related to using a Utf8Const* for a match type. Change match type to be a pointer to a pointer, rather than a pointer to a Class. * defineclass.cc (handleCodeAttribute): Initialize method->deferred. (handleMethodsEnd): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@72886 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/java/ChangeLog | 25 +++++++++++++ gcc/java/class.c | 83 ++++++++++++++++++++++++++++++++++++------- gcc/java/decl.c | 18 ++++++++++ gcc/java/except.c | 48 ++++++++++++++----------- gcc/java/java-tree.h | 26 +++++++++++--- gcc/java/jcf-parse.c | 3 +- gcc/java/lang.c | 45 +++++++++++++++++++++++ libjava/ChangeLog | 26 ++++++++++++++ libjava/defineclass.cc | 2 ++ libjava/exception.cc | 28 ++++++--------- libjava/include/java-interp.h | 31 ++++++++++++++++ libjava/java/lang/Class.h | 10 ++++++ libjava/java/lang/natClass.cc | 65 ++++++++++++++++++++++++++++++--- libjava/resolve.cc | 10 ++++++ 14 files changed, 357 insertions(+), 63 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 16bb513..1458560 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,28 @@ +2003-10-22 Andrew Haley + + * lang.c (LANG_HOOKS_GET_CALLEE_FNDECL): New. + (java_get_callee_fndecl): New. + + * jcf-parse.c (java_parse_file): Call emit_catch_table(). + + * java-tree.h (ctable_decl): New. + (catch_classes): New. + (java_tree_index): Add JTI_CTABLE_DECL, JTI_CATCH_CLASSES. + + * decl.c (java_init_decl_processing): Add catch_class_type. + Add ctable_decl. + Add catch_classes field. + + * class.c (build_indirect_class_ref): Break out from + build_class_ref. + (make_field_value): Check flag_indirect_dispatch. + (make_class_data): Ditto. + Tidy uses of PUSH_FIELD_VALUE. + Add field catch_classes. + (make_catch_class_record): New. + + * java-tree.h (PUSH_FIELD_VALUE): Tidy. + 2003-10-22 Kazu Hirata * jcf-write.c: Follow spelling conventions. diff --git a/gcc/java/class.c b/gcc/java/class.c index 49e1a3d..2aacbd4 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -808,6 +808,20 @@ build_utf8_ref (tree name) return ref; } +/* Like build_class_ref, but instead of a direct reference generate a + pointer into the constant pool. */ + +static tree +build_indirect_class_ref (tree type) +{ + int index; + tree cl; + index = alloc_class_constant (type); + cl = build_ref_from_constant_pool (index); + TREE_TYPE (cl) = promote_type (class_ptr_type); + return cl; +} + /* Build a reference to the class TYPE. Also handles primitive types and array types. */ @@ -820,6 +834,12 @@ build_class_ref (tree type) tree ref, decl_name, decl; if (TREE_CODE (type) == POINTER_TYPE) type = TREE_TYPE (type); + + if (flag_indirect_dispatch + && type != current_class + && TREE_CODE (type) == RECORD_TYPE) + return build_indirect_class_ref (type); + if (TREE_CODE (type) == RECORD_TYPE) { if (TYPE_SIZE (type) == error_mark_node) @@ -902,14 +922,7 @@ build_class_ref (tree type) return ref; } else - { - int index; - tree cl; - index = alloc_class_constant (type); - cl = build_ref_from_constant_pool (index); - TREE_TYPE (cl) = promote_type (class_ptr_type); - return cl; - } + return build_indirect_class_ref (type); } tree @@ -1061,7 +1074,7 @@ make_field_value (tree fdecl) tree finit; int flags; tree type = TREE_TYPE (fdecl); - int resolved = is_compiled_class (type); + int resolved = is_compiled_class (type) && ! flag_indirect_dispatch; START_RECORD_CONSTRUCTOR (finit, field_type_node); PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl))); @@ -1422,7 +1435,8 @@ make_class_data (tree type) super = CLASSTYPE_SUPER (type); if (super == NULL_TREE) super = null_pointer_node; - else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) + else if (! flag_indirect_dispatch + && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super))))) super = build_class_ref (super); else @@ -1492,7 +1506,7 @@ make_class_data (tree type) PUSH_FIELD_VALUE (cons, "method_count", build_int_2 (method_count, 0)); if (flag_indirect_dispatch) - PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node) + PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node); else PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type)); @@ -1505,7 +1519,7 @@ make_class_data (tree type) build_int_2 (static_field_count, 0)); if (flag_indirect_dispatch) - PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node) + PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node); else PUSH_FIELD_VALUE (cons, "vtable", dtable_decl == NULL_TREE ? null_pointer_node @@ -1540,7 +1554,9 @@ make_class_data (tree type) atable_syms_decl)); TREE_CONSTANT (atable_decl) = 1; } - + + PUSH_FIELD_VALUE (cons, "catch_classes", + build1 (ADDR_EXPR, ptr_type_node, ctable_decl)); PUSH_FIELD_VALUE (cons, "interfaces", interfaces); PUSH_FIELD_VALUE (cons, "loader", null_pointer_node); PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0)); @@ -2210,6 +2226,47 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl return the_table; } +/* make an entry for the catch_classes list. */ +tree +make_catch_class_record (tree catch_class, tree classname) +{ + tree entry; + tree type = TREE_TYPE (TREE_TYPE (ctable_decl)); + START_RECORD_CONSTRUCTOR (entry, type); + PUSH_FIELD_VALUE (entry, "address", catch_class); + PUSH_FIELD_VALUE (entry, "classname", classname); + FINISH_RECORD_CONSTRUCTOR (entry); + return entry; +} + + +/* Generate the list of Throwable classes that are caught by exception + handlers in this compilation. */ +void +emit_catch_table (void) +{ + tree table, table_size, array_type; + catch_classes + = tree_cons (NULL, + make_catch_class_record (null_pointer_node, null_pointer_node), + catch_classes); + catch_classes = nreverse (catch_classes); + catch_classes + = tree_cons (NULL, + make_catch_class_record (null_pointer_node, null_pointer_node), + catch_classes); + table_size = build_index_type (build_int_2 (list_length (catch_classes), 0)); + array_type + = build_array_type (TREE_TYPE (TREE_TYPE (ctable_decl)), table_size); + table = build_decl (VAR_DECL, DECL_NAME (ctable_decl), array_type); + DECL_INITIAL (table) = build_constructor (array_type, catch_classes); + TREE_STATIC (table) = 1; + TREE_READONLY (table) = 1; + rest_of_decl_compilation (table, NULL, 1, 0); + ctable_decl = table; +} + + void init_class_processing (void) { diff --git a/gcc/java/decl.c b/gcc/java/decl.c index fa8c939..e23cb120 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -663,6 +663,23 @@ java_init_decl_processing (void) pushdecl (atable_syms_decl); } + { + tree catch_class_type = make_node (RECORD_TYPE); + PUSH_FIELD (catch_class_type, field, "address", utf8const_ptr_type); + PUSH_FIELD (catch_class_type, field, "classname", ptr_type_node); + FINISH_RECORD (catch_class_type); + + ctable_decl + = build_decl (VAR_DECL, get_identifier ("catch_classes"), + build_array_type + (catch_class_type, 0)); + DECL_EXTERNAL (ctable_decl) = 1; + TREE_STATIC (ctable_decl) = 1; + TREE_READONLY (ctable_decl) = 1; + TREE_CONSTANT (ctable_decl) = 1; + pushdecl (ctable_decl); + } + PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type); /* This isn't exactly true, but it is what we have in the source. There is an unresolved issue here, which is whether the vtable @@ -702,6 +719,7 @@ java_init_decl_processing (void) PUSH_FIELD (class_type_node, field, "atable", atable_ptr_type); PUSH_FIELD (class_type_node, field, "atable_syms", symbols_array_ptr_type); + PUSH_FIELD (class_type_node, field, "catch_classes", ptr_type_node); PUSH_FIELD (class_type_node, field, "interfaces", build_pointer_type (class_ptr_type)); PUSH_FIELD (class_type_node, field, "loader", ptr_type_node); diff --git a/gcc/java/except.c b/gcc/java/except.c index 6aeff65..dc97b42f 100644 --- a/gcc/java/except.c +++ b/gcc/java/except.c @@ -313,46 +313,52 @@ prepare_eh_table_type (tree type) { tree exp; - /* The "type" (metch_info) in a (Java) exception table is one: + /* The "type" (match_info) in a (Java) exception table is a pointer to: * a) NULL - meaning match any type in a try-finally. - * b) a pointer to a (compiled) class (low-order bit 0). - * c) a pointer to the Utf8Const name of the class, plus one - * (which yields a value with low-order bit 1). */ + * b) a pointer to a pointer to a class. + * c) a pointer to a pointer to a utf8_ref. The pointer is + * rewritten to point to the appropriate class. */ if (type == NULL_TREE) exp = NULL_TREE; - else if (is_compiled_class (type)) - exp = build_class_ref (type); + else if (is_compiled_class (type) && !flag_indirect_dispatch) + { + char buf[64]; + tree decl; + sprintf (buf, "%s_ref", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node); + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_THIS_VOLATILE (decl) = 0; + DECL_INITIAL (decl) = build_class_ref (type); + layout_decl (decl, 0); + pushdecl (decl); + rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); + make_decl_rtl (decl, (char*) 0); + exp = build1 (ADDR_EXPR, ptr_type_node, decl); + } else { - tree ctype = make_node (RECORD_TYPE); - tree field = NULL_TREE; - tree cinit, decl; + tree decl; tree utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type))); char buf[64]; sprintf (buf, "%s_ref", IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)))); - PUSH_FIELD (ctype, field, "dummy", ptr_type_node); - PUSH_FIELD (ctype, field, "utf8", utf8const_ptr_type); - FINISH_RECORD (ctype); - START_RECORD_CONSTRUCTOR (cinit, ctype); - PUSH_FIELD_VALUE (cinit, "dummy", - convert (ptr_type_node, integer_minus_one_node)); - PUSH_FIELD_VALUE (cinit, "utf8", utf8_ref); - FINISH_RECORD_CONSTRUCTOR (cinit); - TREE_CONSTANT (cinit) = 1; - decl = build_decl (VAR_DECL, get_identifier (buf), ctype); + decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type); TREE_STATIC (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; TREE_READONLY (decl) = 1; TREE_THIS_VOLATILE (decl) = 0; - DECL_INITIAL (decl) = cinit; layout_decl (decl, 0); pushdecl (decl); rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); make_decl_rtl (decl, (char*) 0); - exp = build1 (ADDR_EXPR, build_pointer_type (ctype), decl); + exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl); + catch_classes = tree_cons (NULL, make_catch_class_record (exp, utf8_ref), catch_classes); } return exp; } diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 42f99b5..7b5a397 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -167,6 +167,9 @@ extern int compiling_from_source; otable. */ #define atable_syms_decl java_global_trees [JTI_ATABLE_SYMS_DECL] +#define ctable_decl java_global_trees [JTI_CTABLE_DECL] +#define catch_classes java_global_trees [JTI_CATCH_CLASSES] + extern int flag_emit_class_files; extern int flag_filelist_file; @@ -424,6 +427,9 @@ enum java_tree_index JTI_ATABLE_DECL, JTI_ATABLE_SYMS_DECL, + JTI_CTABLE_DECL, + JTI_CATCH_CLASSES, + JTI_PREDEF_FILENAMES, JTI_MAX @@ -629,6 +635,8 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; java_global_trees[JTI_SYMBOLS_ARRAY_TYPE] #define symbols_array_ptr_type \ java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE] +#define class_refs_decl \ + Jjava_global_trees[TI_CLASS_REFS_DECL] #define end_params_node \ java_global_trees[JTI_END_PARAMS_NODE] @@ -1320,6 +1328,9 @@ extern void java_expand_body (tree); extern int get_symbol_table_index (tree, tree *); +extern tree make_catch_class_record (tree, tree); +extern void emit_catch_table (void); + #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) /* Access flags etc for a method (a FUNCTION_DECL): */ @@ -1678,11 +1689,16 @@ extern tree *type_map; /* Append a field initializer to CONS for a field with the given VALUE. NAME is a char* string used for error checking; the initializer must be specified in order. */ - #define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\ - tree field = TREE_CHAIN(CONS);\ - if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\ - CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\ - TREE_CHAIN(CONS) = TREE_CHAIN (field); } +#define PUSH_FIELD_VALUE(CONS, NAME, VALUE) \ +do \ +{ \ + tree field = TREE_CHAIN(CONS); \ + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) \ + abort(); \ + CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS)); \ + TREE_CHAIN(CONS) = TREE_CHAIN (field); \ +} \ +while (0) /* Finish creating a record CONSTRUCTOR CONS. */ #define FINISH_RECORD_CONSTRUCTOR(CONS) \ diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index de4b213..7570f86 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -632,7 +632,7 @@ jcf_parse (JCF* jcf) if (CLASS_PARSED_P (current_class)) { /* FIXME - where was first time */ - fatal_error ("reading class %s for the second time from %s", + fatal_error (stderr, "READING CLASS %s for the second time from %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))), jcf->filename); } @@ -1137,6 +1137,7 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED) (get_identifier ("atable"), atable_decl, atable_methods, atable_syms_decl, ptr_type_node); } + emit_catch_table (); } write_resource_constructor (); diff --git a/gcc/java/lang.c b/gcc/java/lang.c index ee476b2..615d250 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -68,6 +68,7 @@ static void dump_compound_expr (dump_info_p, tree); static bool java_decl_ok_for_sibcall (tree); static int java_estimate_num_insns (tree); static int java_start_inlining (tree); +static tree java_get_callee_fndecl (tree); #ifndef TARGET_OBJECT_SUFFIX # define TARGET_OBJECT_SUFFIX ".o" @@ -263,6 +264,9 @@ struct language_function GTY(()) #undef LANG_HOOKS_DECL_OK_FOR_SIBCALL #define LANG_HOOKS_DECL_OK_FOR_SIBCALL java_decl_ok_for_sibcall +#undef LANG_HOOKS_GET_CALLEE_FNDECL +#define LANG_HOOKS_GET_CALLEE_FNDECL java_get_callee_fndecl + #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION java_expand_body @@ -1205,4 +1209,45 @@ java_start_inlining (tree fn) return TREE_ASM_WRITTEN (fn) ? 1 : 0; } +/* Given a call_expr, try to figure out what its target might be. In + the case of an indirection via the atable, search for the decl. If + the decl is external, we return NULL. If we don't, the optimizer + will replace the indirection with a direct call, which undoes the + purpose of the atable indirection. */ +static tree +java_get_callee_fndecl (tree call_expr) +{ + tree method, table, element; + + HOST_WIDE_INT index; + + if (TREE_CODE (call_expr) != CALL_EXPR) + return NULL; + method = TREE_OPERAND (call_expr, 0); + STRIP_NOPS (method); + if (TREE_CODE (method) != ARRAY_REF) + return NULL; + table = TREE_OPERAND (method, 0); + if (table != atable_decl) + return NULL; + index = TREE_INT_CST_LOW (TREE_OPERAND (method, 1)); + + /* FIXME: Replace this for loop with a hash table lookup. */ + for (element = atable_methods; element; element = TREE_CHAIN (element)) + { + if (index == 1) + { + tree purpose = TREE_PURPOSE (element); + if (TREE_CODE (purpose) == FUNCTION_DECL + && ! DECL_EXTERNAL (purpose)) + return purpose; + else + return NULL; + } + --index; + } + + return NULL; +} + #include "gt-java-lang.h" diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 742e94b..72b4d6c 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,29 @@ +2003-10-22 Andrew Haley + + * java/lang/natClass.cc (initializeClass): Call + _Jv_linkExceptionClassTable. + (_Jv_LinkSymbolTable): Call )_Jv_ThrowNoSuchMethodError. Call + _Jv_Defer_Resolution on a method whose ncode is NULL. + (_Jv_linkExceptionClassTable): New function. + (_Jv_LayoutVTableMethods): If superclass looks like a constant pool + entry, look it up. + * java/lang/Class.h (struct _Jv_CatchClass): New. + (_Jv_linkExceptionClassTable): New friend. + (_Jv_Defer_Resolution): New friend. + (class Class.catch_classes): New field. + * include/java-interp.h (Jv_Defer_Resolution): New method. + (_Jv_PrepareClass): Make a friend of _Jv_MethodBase. + (_Jv_MethodBase.deferred): New field. + (_Jv_Defer_Resolution): New function. + * resolve.cc (_Jv_PrepareClass): Resolve deferred handlers. + * exception.cc (get_ttype_entry): Change return type to void**. + (PERSONALITY_FUNCTION): Remove all code related to using a + Utf8Const* for a match type. Change match type to be a pointer to + a pointer, rather than a pointer to a Class. + * defineclass.cc (handleCodeAttribute): Initialize + method->deferred. + (handleMethodsEnd): Likewise. + 2003-10-23 Rainer Orth * java/lang/natObject.cc (_Jv_ObjectCheckMonitor): Use diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 4cd4f4f..2e8b4d9 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -1270,6 +1270,7 @@ void _Jv_ClassReader::handleCodeAttribute _Jv_InterpMethod *method = (_Jv_InterpMethod*) (_Jv_AllocBytes (size)); + method->deferred = NULL; method->max_stack = max_stack; method->max_locals = max_locals; method->code_length = code_length; @@ -1328,6 +1329,7 @@ void _Jv_ClassReader::handleMethodsEnd () m->self = method; m->function = NULL; def->interpreted_methods[i] = m; + m->deferred = NULL; if ((method->accflags & Modifier::STATIC)) { diff --git a/libjava/exception.cc b/libjava/exception.cc index 9647d44..088d482 100644 --- a/libjava/exception.cc +++ b/libjava/exception.cc @@ -161,7 +161,7 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, return p; } -static jclass +static void ** get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) { _Unwind_Ptr ptr; @@ -169,7 +169,7 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) i *= size_of_encoded_value (info->ttype_encoding); read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr); - return reinterpret_cast(ptr); + return reinterpret_cast(ptr); } @@ -336,23 +336,15 @@ PERSONALITY_FUNCTION (int version, { // Positive filter values are handlers. - jclass catch_type = get_ttype_entry (context, &info, ar_filter); + void **catch_word = get_ttype_entry (context, &info, ar_filter); + jclass catch_type = (jclass)*catch_word; + + // FIXME: This line is a kludge to work around exception + // handlers written in C++, which don't yet use indirect + // dispatch. + if (catch_type == *(void **)&java::lang::Class::class$) + catch_type = (jclass)catch_word; - typedef struct { - int __attribute__ ((mode (pointer))) dummy; - Utf8Const *utf8; - } utf8_hdr; - utf8_hdr *p = (utf8_hdr *)catch_type; - if (p->dummy == -1) - { - using namespace gnu::gcj::runtime; - java::lang::Class *klass - = StackTrace::getClass ((gnu::gcj::RawData *)ip); - java::lang::ClassLoader *loader - = klass ? klass->getClassLoaderInternal () : NULL; - catch_type = _Jv_FindClass (p->utf8, loader); - } - if (_Jv_IsInstanceOf (xh->value, catch_type)) { handler_switch_value = ar_filter; diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h index c801274..94acfae 100644 --- a/libjava/include/java-interp.h +++ b/libjava/include/java-interp.h @@ -88,6 +88,12 @@ protected: // Size of raw arguments. _Jv_ushort args_raw_size; + // Chain of addresses to fill in. See _Jv_Defer_Resolution. + void *deferred; + + friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); + friend void _Jv_PrepareClass(jclass); + public: _Jv_Method *get_method () { @@ -167,8 +173,33 @@ class _Jv_InterpClass : public java::lang::Class #endif friend _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass); + friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); }; +// We have an interpreted class CL and we're trying to find the +// address of the ncode of a method METH. That interpreted class +// hasn't yet been prepared, so we defer fixups until they are ready. +// To do this, we create a chain of fixups that will be resolved by +// _Jv_PrepareClass. +extern inline void +_Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **address) +{ + int i; + _Jv_InterpClass *self = (_Jv_InterpClass *)cl; + for (i = 0; i < self->method_count; i++) + { + _Jv_Method *m = &self->methods[i]; + if (m == meth) + { + _Jv_MethodBase *imeth = self->interpreted_methods[i]; + *address = imeth->deferred; + imeth->deferred = address; + return; + } + } + return; +} + extern inline _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass) { diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index cdfdd7d..01761af 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -131,6 +131,12 @@ struct _Jv_AddressTable void *addresses[]; }; +struct _Jv_CatchClass +{ + java::lang::Class **address; + _Jv_Utf8Const *classname; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -336,6 +342,7 @@ private: friend void _Jv_LayoutVTableMethods (jclass klass); friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); friend void _Jv_MakeVTable (jclass); + friend void _Jv_linkExceptionClassTable (jclass); friend jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags); @@ -365,6 +372,8 @@ private: friend void _Jv_PrepareClass (jclass); friend void _Jv_PrepareMissingMethods (jclass base, jclass iface_class); + friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); + friend class _Jv_ClassReader; friend class _Jv_InterpClass; friend class _Jv_InterpMethod; @@ -414,6 +423,7 @@ private: _Jv_MethodSymbol *otable_syms; _Jv_AddressTable *atable; _Jv_MethodSymbol *atable_syms; + _Jv_CatchClass *catch_classes; // Interfaces implemented by this class. jclass *interfaces; // The class loader for this class. diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index c9b7014..2d80ce2 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -12,6 +12,7 @@ details. */ #include #include +#include #pragma implementation "Class.h" @@ -56,7 +57,7 @@ details. */ #include #include - +#include using namespace gcj; @@ -796,6 +797,8 @@ java::lang::Class::initializeClass (void) if (otable || atable) _Jv_LinkSymbolTable(this); + _Jv_linkExceptionClassTable (this); + // Steps 8, 9, 10, 11. try { @@ -1541,14 +1544,18 @@ _Jv_LinkSymbolTable(jclass klass) for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++) { + // FIXME: Why are we passing NULL as the class loader? jclass target_class = _Jv_FindClass (sym.class_name, NULL); _Jv_Method *meth = NULL; const _Jv_Utf8Const *signature = sym.signature; - // FIXME: This should be special index for ThrowNoSuchMethod(). - klass->otable->offsets[index] = -1; - + { + static char *bounce = (char *)_Jv_ThrowNoSuchMethodError; + ptrdiff_t offset = (char *)(klass->vtable) - bounce; + klass->otable->offsets[index] = offset; + } + if (target_class == NULL) continue; @@ -1658,6 +1665,7 @@ _Jv_LinkSymbolTable(jclass klass) for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++) { + // FIXME: Why are we passing NULL as the class loader? jclass target_class = _Jv_FindClass (sym.class_name, NULL); _Jv_Method *meth = NULL; const _Jv_Utf8Const *signature = sym.signature; @@ -1687,7 +1695,13 @@ _Jv_LinkSymbolTable(jclass klass) sym.signature); if (meth != NULL) - klass->atable->addresses[index] = meth->ncode; + { + if (meth->ncode) // Maybe abstract? + klass->atable->addresses[index] = meth->ncode; + else if (_Jv_IsInterpretedClass (target_class)) + _Jv_Defer_Resolution (target_class, meth, + &klass->atable->addresses[index]); + } else klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError; @@ -1743,6 +1757,27 @@ _Jv_LinkSymbolTable(jclass klass) } } + +// For each catch_record in the list of caught classes, fill in the +// address field. +void +_Jv_linkExceptionClassTable (jclass self) +{ + struct _Jv_CatchClass *catch_record = self->catch_classes; + if (!catch_record || catch_record->classname) + return; + catch_record++; + while (catch_record->classname) + { + jclass target_class = _Jv_FindClass (catch_record->classname, + self->getClassLoaderInternal ()); + *catch_record->address = target_class; + catch_record++; + } + self->catch_classes->classname = (_Jv_Utf8Const *)-1; +} + + // Returns true if METH should get an entry in a VTable. static jboolean isVirtualMethod (_Jv_Method *meth) @@ -1772,6 +1807,26 @@ _Jv_LayoutVTableMethods (jclass klass) jclass superclass = klass->superclass; + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + + // If superclass looks like a constant pool entry, + // resolve it now. + if ((uaddr)superclass < (uaddr)klass->constants.size) + { + if (klass->state < JV_STATE_LINKED) + { + _Jv_Utf8Const *name = klass->constants.data[(int)superclass].utf8; + superclass = _Jv_FindClass (name, klass->loader); + if (! superclass) + { + jstring str = _Jv_NewStringUTF (name->data); + throw new java::lang::NoClassDefFoundError (str); + } + } + else + superclass = klass->constants.data[(int)superclass].clazz; + } + if (superclass != NULL && superclass->vtable_method_count == -1) { JvSynchronize sync (superclass); diff --git a/libjava/resolve.cc b/libjava/resolve.cc index ce1af8d..d71e125 100644 --- a/libjava/resolve.cc +++ b/libjava/resolve.cc @@ -575,6 +575,16 @@ _Jv_PrepareClass(jclass klass) _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); _Jv_VerifyMethod (im); clz->methods[i].ncode = im->ncode (); + + // Resolve ctable entries pointing to this method. See + // _Jv_Defer_Resolution. + void **code = (void **)imeth->deferred; + while (code) + { + void **target = (void **)*code; + *code = clz->methods[i].ncode; + code = target; + } } } -- 2.7.4