Java/12725: Binary Compatibility
Andrew Haley
aph@redhat.com
Wed Oct 22 17:44:00 GMT 2003
This patch handles calls to interpreted code from native code, even
the very tricky problem of a class in a catch handler being provided
by interpreted code.
You really can do something like
public class one
{
public static void main (String[] s)
{
try
{
foo.main (s);
}
catch (Kludge _)
{
System.out.println (_);
}
}
}
public class foo
{
public static void main (String argv[]) throws Kludge
{
throw new Kludge();
}
}
public class Kludge extends Exception
{
public String toString() { return "zounds!"; }
}
$ gcj one.java foo.java -findirect-dispatch --main=one
$ gcj -fpic foo.java -o lib-foo.so -shared -findirect-dispatch
$ gcj -C Kludge.java
$ ./a.out
zounds!
And this runs an executable which dynamically loads lib-foo.so and
invokes the interpreter to load Kludge.class.
Also, you have the additional benefit that you can compile and run
JARs with external dependencies which are resolved at runtime.
It's still a prototype, because there are some remaining issues:
* Resolving static methods and classes is not thread safe.
* There are many linear (rather than hash table) searches, both at
compile time and run time.
* There is functional overlap between the constant pool and the
address and offset tables. Perhaps they should be unified.
* The way handlers for catch regions are handled is rather inelegant.
* CNI code is not binary compatible.
... and probably more.
Still, as Binary Compatibility is to be an important feature of gcj
3.5 I want the prototype to be available to users of gcj 3.4. It
won't be enabled without -findirect-dispatch.
Andrew.
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.
Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.171
diff -c -2 -p -r1.171 class.c
*** gcc/java/class.c 9 Oct 2003 16:21:56 -0000 1.171
--- gcc/java/class.c 22 Oct 2003 17:19:46 -0000
*************** build_utf8_ref (tree name)
*** 809,812 ****
--- 809,826 ----
}
+ /* 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. */
*************** build_class_ref (tree type)
*** 821,824 ****
--- 835,844 ----
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)
{
*************** build_class_ref (tree type)
*** 903,914 ****
}
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;
! }
}
--- 923,927 ----
}
else
! return build_indirect_class_ref (type);
}
*************** make_field_value (tree fdecl)
*** 1062,1066 ****
int flags;
tree type = TREE_TYPE (fdecl);
! int resolved = is_compiled_class (type);
START_RECORD_CONSTRUCTOR (finit, field_type_node);
--- 1075,1079 ----
int flags;
tree type = TREE_TYPE (fdecl);
! int resolved = is_compiled_class (type) && ! flag_indirect_dispatch;
START_RECORD_CONSTRUCTOR (finit, field_type_node);
*************** make_class_data (tree type)
*** 1423,1427 ****
if (super == NULL_TREE)
super = null_pointer_node;
! else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
&& assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super)))))
super = build_class_ref (super);
--- 1436,1441 ----
if (super == NULL_TREE)
super = null_pointer_node;
! 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);
*************** make_class_data (tree type)
*** 1493,1497 ****
if (flag_indirect_dispatch)
! PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node)
else
PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
--- 1507,1511 ----
if (flag_indirect_dispatch)
! PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
else
PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
*************** make_class_data (tree type)
*** 1506,1510 ****
if (flag_indirect_dispatch)
! PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
else
PUSH_FIELD_VALUE (cons, "vtable",
--- 1520,1524 ----
if (flag_indirect_dispatch)
! PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
else
PUSH_FIELD_VALUE (cons, "vtable",
*************** make_class_data (tree type)
*** 1541,1545 ****
TREE_CONSTANT (atable_decl) = 1;
}
!
PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
--- 1555,1561 ----
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);
*************** emit_symbol_table (tree name, tree the_t
*** 2210,2213 ****
--- 2226,2270 ----
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
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.168
diff -c -2 -p -r1.168 decl.c
*** gcc/java/decl.c 9 Oct 2003 16:21:56 -0000 1.168
--- gcc/java/decl.c 22 Oct 2003 17:19:46 -0000
*************** java_init_decl_processing (void)
*** 664,667 ****
--- 664,684 ----
}
+ {
+ 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.
*************** java_init_decl_processing (void)
*** 703,706 ****
--- 720,724 ----
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));
Index: gcc/java/except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/except.c,v
retrieving revision 1.39
diff -c -2 -p -r1.39 except.c
*** gcc/java/except.c 20 Aug 2003 17:27:54 -0000 1.39
--- gcc/java/except.c 22 Oct 2003 17:19:46 -0000
*************** prepare_eh_table_type (tree type)
*** 314,346 ****
tree exp;
! /* The "type" (metch_info) in a (Java) exception table is one:
* 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). */
if (type == NULL_TREE)
exp = NULL_TREE;
! else if (is_compiled_class (type))
! exp = build_class_ref (type);
else
{
! 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];
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);
TREE_STATIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
--- 314,352 ----
tree exp;
! /* The "type" (metch_info) in a (Java) exception table is a pointer tone:
* a) NULL - meaning match any type in a try-finally.
! * b) a pointer to pointer to a class.
! * c) a pointer to 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) && !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 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;
*************** prepare_eh_table_type (tree type)
*** 348,357 ****
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);
}
return exp;
--- 354,363 ----
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;
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.185
diff -c -2 -p -r1.185 java-tree.h
*** gcc/java/java-tree.h 1 Oct 2003 16:22:11 -0000 1.185
--- gcc/java/java-tree.h 22 Oct 2003 17:19:47 -0000
*************** extern int compiling_from_source;
*** 168,171 ****
--- 168,174 ----
#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;
*************** enum java_tree_index
*** 425,428 ****
--- 428,435 ----
JTI_ATABLE_SYMS_DECL,
+ JTI_CTABLE_DECL,
+ JTI_CATCH_CLASSES,
+
+
JTI_PREDEF_FILENAMES,
*************** extern GTY(()) tree java_global_trees[JT
*** 630,633 ****
--- 637,642 ----
#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 \
*************** extern void java_expand_body (tree);
*** 1321,1324 ****
--- 1330,1338 ----
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)
*************** extern tree *type_map;
*** 1679,1687 ****
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); }
/* Finish creating a record CONSTRUCTOR CONS. */
--- 1693,1706 ----
NAME is a char* string used for error checking;
the initializer must be specified in order. */
! #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. */
Index: gcc/java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.148
diff -c -2 -p -r1.148 jcf-parse.c
*** gcc/java/jcf-parse.c 1 Oct 2003 16:22:11 -0000 1.148
--- gcc/java/jcf-parse.c 22 Oct 2003 17:19:47 -0000
*************** java_parse_file (int set_yydebug ATTRIBU
*** 1138,1141 ****
--- 1138,1142 ----
atable_decl, atable_methods, atable_syms_decl, ptr_type_node);
}
+ emit_catch_table ();
}
Index: gcc/java/lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.143
diff -c -2 -p -r1.143 lang.c
*** gcc/java/lang.c 28 Sep 2003 04:56:34 -0000 1.143
--- gcc/java/lang.c 22 Oct 2003 17:19:48 -0000
*************** static bool java_decl_ok_for_sibcall (tr
*** 69,72 ****
--- 69,73 ----
static int java_estimate_num_insns (tree);
static int java_start_inlining (tree);
+ static tree java_get_callee_fndecl (tree);
#ifndef TARGET_OBJECT_SUFFIX
*************** struct language_function GTY(())
*** 264,267 ****
--- 265,271 ----
#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
*************** java_start_inlining (tree fn)
*** 1204,1207 ****
--- 1208,1252 ----
that are not yet expanded. */
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;
}
Index: libjava/defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.34
diff -c -2 -p -r1.34 defineclass.cc
*** libjava/defineclass.cc 29 Jul 2003 17:12:54 -0000 1.34
--- libjava/defineclass.cc 22 Oct 2003 17:19:54 -0000
*************** void _Jv_ClassReader::handleCodeAttribut
*** 1271,1274 ****
--- 1271,1275 ----
(_Jv_InterpMethod*) (_Jv_AllocBytes (size));
+ method->deferred = NULL;
method->max_stack = max_stack;
method->max_locals = max_locals;
*************** void _Jv_ClassReader::handleMethodsEnd (
*** 1329,1332 ****
--- 1330,1334 ----
m->function = NULL;
def->interpreted_methods[i] = m;
+ m->deferred = NULL;
if ((method->accflags & Modifier::STATIC))
Index: libjava/exception.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/exception.cc,v
retrieving revision 1.23
diff -c -2 -p -r1.23 exception.cc
*** libjava/exception.cc 20 Aug 2003 17:27:55 -0000 1.23
--- libjava/exception.cc 22 Oct 2003 17:19:54 -0000
*************** parse_lsda_header (_Unwind_Context *cont
*** 162,166 ****
}
! static jclass
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
{
--- 162,166 ----
}
! static void **
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
{
*************** get_ttype_entry (_Unwind_Context *contex
*** 170,174 ****
read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
! return reinterpret_cast<jclass>(ptr);
}
--- 170,174 ----
read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
! return reinterpret_cast<void **>(ptr);
}
*************** PERSONALITY_FUNCTION (int version,
*** 337,357 ****
// Positive filter values are handlers.
! jclass catch_type = get_ttype_entry (context, &info, ar_filter);
- 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))
{
--- 337,349 ----
// Positive filter values are handlers.
! 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;
if (_Jv_IsInstanceOf (xh->value, catch_type))
{
Index: libjava/resolve.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/resolve.cc,v
retrieving revision 1.42
diff -c -2 -p -r1.42 resolve.cc
*** libjava/resolve.cc 25 Sep 2003 07:46:18 -0000 1.42
--- libjava/resolve.cc 22 Oct 2003 17:19:55 -0000
*************** _Jv_PrepareClass(jclass klass)
*** 576,579 ****
--- 576,589 ----
_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;
+ }
}
}
Index: libjava/include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.22
diff -c -2 -p -r1.22 java-interp.h
*** libjava/include/java-interp.h 24 Jan 2003 19:58:21 -0000 1.22
--- libjava/include/java-interp.h 22 Oct 2003 17:19:55 -0000
*************** protected:
*** 89,92 ****
--- 89,98 ----
_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 ()
*************** class _Jv_InterpClass : public java::lan
*** 168,172 ****
--- 174,203 ----
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 **
Index: libjava/java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.60
diff -c -2 -p -r1.60 Class.h
*** libjava/java/lang/Class.h 9 Oct 2003 16:24:55 -0000 1.60
--- libjava/java/lang/Class.h 22 Oct 2003 17:19:55 -0000
*************** struct _Jv_AddressTable
*** 132,135 ****
--- 132,141 ----
};
+ struct _Jv_CatchClass
+ {
+ java::lang::Class **address;
+ _Jv_Utf8Const *classname;
+ };
+
#define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
*************** private:
*** 336,339 ****
--- 342,346 ----
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,
*************** private:
*** 365,368 ****
--- 372,377 ----
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;
*************** private:
*** 414,417 ****
--- 423,427 ----
_Jv_AddressTable *atable;
_Jv_MethodSymbol *atable_syms;
+ _Jv_CatchClass *catch_classes;
// Interfaces implemented by this class.
jclass *interfaces;
Index: libjava/java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.66
diff -c -2 -p -r1.66 natClass.cc
*** libjava/java/lang/natClass.cc 9 Oct 2003 16:24:55 -0000 1.66
--- libjava/java/lang/natClass.cc 22 Oct 2003 17:19:56 -0000
*************** details. */
*** 13,16 ****
--- 13,17 ----
#include <limits.h>
#include <string.h>
+ #include <stddef.h>
#pragma implementation "Class.h"
*************** details. */
*** 57,61 ****
#include <java-cpool.h>
!
--- 58,62 ----
#include <java-cpool.h>
! #include <java-interp.h>
*************** java::lang::Class::initializeClass (void
*** 835,838 ****
--- 836,841 ----
_Jv_LinkSymbolTable(this);
+ _Jv_linkExceptionClassTable (this);
+
// Steps 8, 9, 10, 11.
try
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1580,1583 ****
--- 1583,1587 ----
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;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1585,1591 ****
const _Jv_Utf8Const *signature = sym.signature;
! // FIXME: This should be special index for ThrowNoSuchMethod().
! klass->otable->offsets[index] = -1;
!
if (target_class == NULL)
continue;
--- 1589,1598 ----
const _Jv_Utf8Const *signature = sym.signature;
! {
! static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
! ptrdiff_t offset = (char *)(klass->vtable) - bounce;
! klass->otable->offsets[index] = offset;
! }
!
if (target_class == NULL)
continue;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1697,1700 ****
--- 1704,1708 ----
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;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1726,1730 ****
if (meth != NULL)
! klass->atable->addresses[index] = meth->ncode;
else
klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError;
--- 1734,1744 ----
if (meth != NULL)
! {
! 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;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1782,1785 ****
--- 1796,1820 ----
}
+
+ // 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
*************** _Jv_LayoutVTableMethods (jclass klass)
*** 1810,1813 ****
--- 1845,1868 ----
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)
More information about the Java-patches
mailing list