lang.c (LANG_HOOKS_GET_CALLEE_FNDECL): New.
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. From-SVN: r72886
This commit is contained in:
parent
c769a35d59
commit
904715853c
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
else if (is_compiled_class (type) && !flag_indirect_dispatch)
|
||||
{
|
||||
tree ctype = make_node (RECORD_TYPE);
|
||||
tree field = NULL_TREE;
|
||||
tree cinit, decl;
|
||||
tree utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
|
||||
char buf[64];
|
||||
tree decl;
|
||||
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);
|
||||
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) = cinit;
|
||||
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, build_pointer_type (ctype), decl);
|
||||
exp = build1 (ADDR_EXPR, ptr_type_node, decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
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))));
|
||||
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;
|
||||
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 (utf8const_ptr_type), decl);
|
||||
catch_classes = tree_cons (NULL, make_catch_class_record (exp, utf8_ref), catch_classes);
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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 ();
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user