summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraph <aph@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-24 09:29:43 +0000
committeraph <aph@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-24 09:29:43 +0000
commite164eae76e4e677e729d62cf39e1c51e4ef7f311 (patch)
tree8c726fb42c811bb6652ba1a759bae78c2c8d9378
parentaeac46d4895e26ae7c0fb8976229512eaa26a922 (diff)
downloadgcc-e164eae76e4e677e729d62cf39e1c51e4ef7f311.tar.gz
2003-10-22 Andrew Haley <aph@redhat.com>
* 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 <aph@redhat.com> * 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
-rw-r--r--gcc/java/ChangeLog25
-rw-r--r--gcc/java/class.c83
-rw-r--r--gcc/java/decl.c18
-rw-r--r--gcc/java/except.c48
-rw-r--r--gcc/java/java-tree.h26
-rw-r--r--gcc/java/jcf-parse.c3
-rw-r--r--gcc/java/lang.c45
-rw-r--r--libjava/ChangeLog26
-rw-r--r--libjava/defineclass.cc2
-rw-r--r--libjava/exception.cc28
-rw-r--r--libjava/include/java-interp.h31
-rw-r--r--libjava/java/lang/Class.h10
-rw-r--r--libjava/java/lang/natClass.cc65
-rw-r--r--libjava/resolve.cc10
14 files changed, 357 insertions, 63 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 16bb5135d56..1458560aad1 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,28 @@
+2003-10-22 Andrew Haley <aph@redhat.com>
+
+ * 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 <kazu@cs.umass.edu>
* jcf-write.c: Follow spelling conventions.
diff --git a/gcc/java/class.c b/gcc/java/class.c
index 49e1a3db5cf..2aacbd42e04 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 fa8c939cd47..e23cb120c3a 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 6aeff65ea25..dc97b42fabf 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 42f99b57e95..7b5a397ecdb 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 de4b213a6c6..7570f861248 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 ee476b2fc9e..615d250c018 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 742e94b036c..72b4d6cb647 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,29 @@
+2003-10-22 Andrew Haley <aph@redhat.com>
+
+ * 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 <ro@TechFak.Uni-Bielefeld.DE>
* java/lang/natObject.cc (_Jv_ObjectCheckMonitor): Use
diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc
index 4cd4f4f1936..2e8b4d97434 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 9647d446d18..088d48268e3 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<jclass>(ptr);
+ return reinterpret_cast<void **>(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 c801274f4cb..94acfae281f 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 cdfdd7d2349..01761af5cec 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 c9b70147b61..2d80ce2133b 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -12,6 +12,7 @@ details. */
#include <limits.h>
#include <string.h>
+#include <stddef.h>
#pragma implementation "Class.h"
@@ -56,7 +57,7 @@ details. */
#include <gnu/gcj/RawData.h>
#include <java-cpool.h>
-
+#include <java-interp.h>
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 ce1af8d2586..d71e1251ff0 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;
+ }
}
}