diff options
author | Bryce McKinlay <mckinlay@redhat.com> | 2004-11-05 19:30:12 +0000 |
---|---|---|
committer | Bryce McKinlay <mckinlay@redhat.com> | 2004-11-05 19:30:12 +0000 |
commit | fc81ff3a0b10fdc1c8d73677c95726734482d4a4 (patch) | |
tree | c7a97f592aa97e90ce9671b2548dac6bc5657b51 | |
parent | 70b9be8bc1fa69eadb2882e894ee95ef62c3989c (diff) |
gcc/java:
2004-11-05 Bryce McKinlay <mckinlay@redhat.com>
* link.cc: Include VerifyError.h.
(_Jv_Linker::verify_type_assertions): New. Read and evaluate entries
in the type assertion table.
* include/execution.h (_Jv_CompiledEngine::do_verify): Use
verify_type_assertions.
* include/jvm.h (_Jv_Linker::verify_type_assertions): declare.
* java/lang/Class.h (JV_ASSERT_END_OF_TABLE,
JV_ASSERT_TYPES_COMPATIBLE, JV_ASSERT_IS_INSTANTIABLE): Declare
assertion code values.
(struct _Jv_TypeAssertion): Declare.
(assertion_table): New class field.
(verify): Remove class field.
libjava:
2004-11-05 Bryce McKinlay <mckinlay@redhat.com>
* class.c (make_class_data): Call emit_assertion_table to set the
'assertion_table' field.
(build_signature_for_libgcj): Move here from expr.c.
(add_assertion_table_entry): New function. Callback for assertion
hashtable traversal.
(emit_assertion_table): New. Take class argument, and generate
assertion table DECL based on the TYPE_ASSERTIONS hashtable.
* decl.c (init_decl_processing): Define assertion_entry_type record.
Push 'assertion_table' class field instead of 'verify'.
* expr.c (type_assertion_eq): Compare 'assertion_code' field.
(type_assertion_hash): Include 'assertion_code' in hash.
(add_type_assertion): Rewritten. Take class and assertion_code
arguments. Add assertions to the TYPE_ASSERTIONS hashtable.
(can_widen_reference_to): Use new add_type_assertion() arguments.
* java-tree.h (java_tree_index): Add JTI_ASSERTION_ENTRY_TYPE,
JTI_ASSERTION_TABLE_TYPE. Remove JTI_VERIFY_IDENTIFIER_NODE.
(verify_identifier_node): Removed.
(assertion_entry_type, assertion_table_type): New.
(ASSERTION_TYPES_COMPATIBLE, ASSERTION_IS_INSTANTIABLE): New. Type
assertion code definitions.
(struct type_assertion): Add assertion_code. Rename 'source_type'
and 'target_type' to 'op1' and 'op2'.
(add_type_assertion): Declare.
(lang_printable_name_wls): Remove unused definition.
* verify-glue.c: (vfy_is_assignable_from): New. Call
add_type_assertion
to emit runtime assertion.
(vfy_note_stack_type): Clean up non-C90 declarations.
(vfy_note_local_type): Likewise.
* verify.h (vfy_is_assignable_from): Declare.
* verify-impl.c (is_assignable_from_slow): Remove unused function.
(ref_compatible): Rename arguments. Call vfy_is_assignable_from()
instead of is_assignable_from_slow().
(types_compatible): Reinstate ref_compatible() call.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcj-abi-2-dev-branch@90135 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/java/ChangeLog | 36 | ||||
-rw-r--r-- | gcc/java/class.c | 112 | ||||
-rw-r--r-- | gcc/java/decl.c | 12 | ||||
-rw-r--r-- | gcc/java/expr.c | 135 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 31 | ||||
-rw-r--r-- | gcc/java/verify-glue.c | 31 | ||||
-rw-r--r-- | gcc/java/verify-impl.c | 87 | ||||
-rw-r--r-- | gcc/java/verify.h | 1 | ||||
-rw-r--r-- | libjava/ChangeLog | 15 | ||||
-rw-r--r-- | libjava/include/execution.h | 6 | ||||
-rw-r--r-- | libjava/include/jvm.h | 1 | ||||
-rw-r--r-- | libjava/java/lang/Class.h | 21 | ||||
-rw-r--r-- | libjava/link.cc | 63 |
13 files changed, 350 insertions, 201 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index b620954f5a2..c3477b6d482 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,39 @@ +2004-11-05 Bryce McKinlay <mckinlay@redhat.com> + + * class.c (make_class_data): Call emit_assertion_table to set the + 'assertion_table' field. + (build_signature_for_libgcj): Move here from expr.c. + (add_assertion_table_entry): New function. Callback for assertion + hashtable traversal. + (emit_assertion_table): New. Take class argument, and generate + assertion table DECL based on the TYPE_ASSERTIONS hashtable. + * decl.c (init_decl_processing): Define assertion_entry_type record. + Push 'assertion_table' class field instead of 'verify'. + * expr.c (type_assertion_eq): Compare 'assertion_code' field. + (type_assertion_hash): Include 'assertion_code' in hash. + (add_type_assertion): Rewritten. Take class and assertion_code + arguments. Add assertions to the TYPE_ASSERTIONS hashtable. + (can_widen_reference_to): Use new add_type_assertion() arguments. + * java-tree.h (java_tree_index): Add JTI_ASSERTION_ENTRY_TYPE, + JTI_ASSERTION_TABLE_TYPE. Remove JTI_VERIFY_IDENTIFIER_NODE. + (verify_identifier_node): Removed. + (assertion_entry_type, assertion_table_type): New. + (ASSERTION_TYPES_COMPATIBLE, ASSERTION_IS_INSTANTIABLE): New. Type + assertion code definitions. + (struct type_assertion): Add assertion_code. Rename 'source_type' and + 'target_type' to 'op1' and 'op2'. + (add_type_assertion): Declare. + (lang_printable_name_wls): Remove unused definition. + * verify-glue.c: (vfy_is_assignable_from): New. Call add_type_assertion + to emit runtime assertion. + (vfy_note_stack_type): Clean up non-C90 declarations. + (vfy_note_local_type): Likewise. + * verify.h (vfy_is_assignable_from): Declare. + * verify-impl.c (is_assignable_from_slow): Remove unused function. + (ref_compatible): Rename arguments. Call vfy_is_assignable_from() + instead of is_assignable_from_slow(). + (types_compatible): Reinstate ref_compatible() call. + 2004-11-04 Tom Tromey <tromey@redhat.com> * class.c (build_static_field_ref): Reverted previous patch. diff --git a/gcc/java/class.c b/gcc/java/class.c index d01ce72fd96..831b1bcff17 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -62,6 +62,7 @@ static tree maybe_layout_super_class (tree, tree); static void add_miranda_methods (tree, tree); static int assume_compiled (const char *); static tree build_symbol_entry (tree); +static tree emit_assertion_table (tree); struct obstack temporary_obstack; @@ -1852,16 +1853,19 @@ make_class_data (tree type) PUSH_FIELD_VALUE (cons, "idt", null_pointer_node); PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node); PUSH_FIELD_VALUE (cons, "protectionDomain", null_pointer_node); + { - tree verify_method = TYPE_VERIFY_METHOD (type); - tree verify_method_ref - = (verify_method - ? build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (verify_method)), - verify_method) - : null_pointer_node); - PUSH_FIELD_VALUE (cons, "verify" , verify_method_ref); - TYPE_VERIFY_METHOD (type) = NULL; + tree assertion_table_ref; + if (TYPE_ASSERTIONS (type) == NULL) + assertion_table_ref = null_pointer_node; + else + assertion_table_ref = build1 (ADDR_EXPR, + build_pointer_type (assertion_table_type), + emit_assertion_table (type)); + + PUSH_FIELD_VALUE (cons, "assertion_table", assertion_table_ref); } + PUSH_FIELD_VALUE (cons, "hack_signers", null_pointer_node); PUSH_FIELD_VALUE (cons, "chain", null_pointer_node); PUSH_FIELD_VALUE (cons, "aux_info", null_pointer_node); @@ -2548,7 +2552,7 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, return the_table; } -/* make an entry for the catch_classes list. */ +/* Make an entry for the catch_classes list. */ tree make_catch_class_record (tree catch_class, tree classname) { @@ -2593,7 +2597,95 @@ emit_catch_table (tree this_class) rest_of_decl_compilation (table, 1, 0); return table; } - + +/* Given a type, return the signature used by + _Jv_FindClassFromSignature() in libgcj. This isn't exactly the + same as build_java_signature() because we want the canonical array + type. */ + +static tree +build_signature_for_libgcj (tree type) +{ + tree sig, ref; + + sig = build_java_signature (type); + ref = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig), + IDENTIFIER_LENGTH (sig))); + return ref; +} + +/* Add an entry to the type assertion table. Callback used during hashtable + traversal. */ + +static int +add_assertion_table_entry (void **htab_entry, void *ptr) +{ + tree entry; + tree code_val, op1_utf8, op2_utf8; + tree *list = (tree *) ptr; + type_assertion *as = (type_assertion *) *htab_entry; + + code_val = build_int_cst (NULL_TREE, as->assertion_code); + + if (as->op1 == NULL_TREE) + op1_utf8 = null_pointer_node; + else + op1_utf8 = build_signature_for_libgcj (as->op1); + + if (as->op2 == NULL_TREE) + op2_utf8 = null_pointer_node; + else + op2_utf8 = build_signature_for_libgcj (as->op2); + + START_RECORD_CONSTRUCTOR (entry, assertion_entry_type); + PUSH_FIELD_VALUE (entry, "assertion_code", code_val); + PUSH_FIELD_VALUE (entry, "op1", op1_utf8); + PUSH_FIELD_VALUE (entry, "op2", op2_utf8); + FINISH_RECORD_CONSTRUCTOR (entry); + + *list = tree_cons (NULL_TREE, entry, *list); + return true; +} + +/* Generate the type assertion table for CLASS, and return its DECL. */ + +static tree +emit_assertion_table (tree class) +{ + tree null_entry, ctor, table_decl; + tree list = NULL_TREE; + htab_t assertions_htab = TYPE_ASSERTIONS (class); + + /* Iterate through the hash table. */ + htab_traverse (assertions_htab, add_assertion_table_entry, &list); + + /* Finish with a null entry. */ + START_RECORD_CONSTRUCTOR (null_entry, assertion_entry_type); + PUSH_FIELD_VALUE (null_entry, "assertion_code", integer_zero_node); + PUSH_FIELD_VALUE (null_entry, "op1", null_pointer_node); + PUSH_FIELD_VALUE (null_entry, "op2", null_pointer_node); + FINISH_RECORD_CONSTRUCTOR (null_entry); + + list = tree_cons (NULL_TREE, null_entry, list); + + /* Put the list in the right order and make it a constructor. */ + list = nreverse (list); + ctor = build_constructor (assertion_table_type, list); + + table_decl = build_decl (VAR_DECL, mangled_classname ("_type_assert_", class), + assertion_table_type); + + TREE_STATIC (table_decl) = 1; + TREE_READONLY (table_decl) = 1; + TREE_CONSTANT (table_decl) = 1; + DECL_IGNORED_P (table_decl) = 1; + + DECL_INITIAL (table_decl) = ctor; + DECL_ARTIFICIAL (table_decl) = 1; + rest_of_decl_compilation (table_decl, 1, 0); + + return table_decl; +} void init_class_processing (void) diff --git a/gcc/java/decl.c b/gcc/java/decl.c index ca415da38e5..4141e834297 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -735,6 +735,15 @@ java_init_decl_processing (void) one_elt_array_domain_type); symbols_array_ptr_type = build_pointer_type (symbols_array_type); + assertion_entry_type = make_node (RECORD_TYPE); + PUSH_FIELD (assertion_entry_type, field, "assertion_code", integer_type_node); + PUSH_FIELD (assertion_entry_type, field, "op1", utf8const_ptr_type); + PUSH_FIELD (assertion_entry_type, field, "op2", utf8const_ptr_type); + FINISH_RECORD (assertion_entry_type); + + assertion_table_type = build_array_type (assertion_entry_type, + one_elt_array_domain_type); + /* As you're adding items here, please update the code right after this section, so that the filename containing the source code of the pre-defined class gets registered correctly. */ @@ -775,7 +784,6 @@ java_init_decl_processing (void) clinit_identifier_node = get_identifier ("<clinit>"); finit_identifier_node = get_identifier ("finit$"); instinit_identifier_node = get_identifier ("instinit$"); - verify_identifier_node = get_identifier ("__verify"); void_signature_node = get_identifier ("()V"); length_identifier_node = get_identifier ("length"); finalize_identifier_node = get_identifier ("finalize"); @@ -866,7 +874,7 @@ java_init_decl_processing (void) PUSH_FIELD (class_type_node, field, "idt", ptr_type_node); PUSH_FIELD (class_type_node, field, "arrayclass", ptr_type_node); PUSH_FIELD (class_type_node, field, "protectionDomain", ptr_type_node); - PUSH_FIELD (class_type_node, field, "verify", ptr_type_node); + PUSH_FIELD (class_type_node, field, "assertion_table", ptr_type_node); PUSH_FIELD (class_type_node, field, "hack_signers", ptr_type_node); PUSH_FIELD (class_type_node, field, "chain", ptr_type_node); PUSH_FIELD (class_type_node, field, "aux_info", ptr_type_node); diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 4b5874705b9..50c740744e0 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -416,8 +416,9 @@ type_assertion_eq (const void * k1_p, const void * k2_p) { type_assertion k1 = *(type_assertion *)k1_p; type_assertion k2 = *(type_assertion *)k2_p; - return (k1.source_type == k2.source_type - && k1.target_type == k2.target_type); + return (k1.assertion_code == k2.assertion_code + && k1.op1 == k2.op1 + && k1.op2 == k2.op2); } /* Hash a type assertion. */ @@ -426,110 +427,47 @@ static hashval_t type_assertion_hash (const void *p) { const type_assertion *k_p = p; - hashval_t hash = iterative_hash (&k_p->target_type, sizeof k_p->target_type, 0); - return iterative_hash (&k_p->source_type, sizeof k_p->source_type, hash); + hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof + k_p->assertion_code, 0); + hash = iterative_hash (&k_p->op1, sizeof k_p->op1, hash); + return iterative_hash (&k_p->op2, sizeof k_p->op2, hash); } -/* Given a type, return the signature used by - _Jv_FindClassFromSignature() in libgcj. This isn't exactly the - same as build_java_signature() because we want the canonical array - type. */ +/* Add an entry to the type assertion table for the given class. + CLASS is the class for which this assertion will be evaluated by the + runtime during loading/initialization. + ASSERTION_CODE is the 'opcode' or type of this assertion: see java-tree.h. + OP1 and OP2 are the operands. The tree type of these arguments may be + specific to each assertion_code. */ -static tree -build_signature_for_libgcj (tree type) -{ - tree sig, ref; - - sig = build_java_signature (type); - ref = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig), - IDENTIFIER_LENGTH (sig))); - return ref; -} - -/* Add an assertion of the form "source_type is a subclass/ - subinterface of target_type" to the "__verify" function of the - current class. */ - -static void -add_type_assertion (tree source_type, tree target_type) +void +add_type_assertion (tree class, int assertion_code, tree op1, tree op2) { - tree verify_method = TYPE_VERIFY_METHOD (output_class); - tree itype = TREE_TYPE (TREE_TYPE (soft_instanceof_node)); - tree arg; + htab_t assertions_htab; + type_assertion as; + void **as_pp; - if (TYPE_ARRAY_P (source_type)) + assertions_htab = TYPE_ASSERTIONS (class); + if (assertions_htab == NULL) { - // FIXME: This is just a placeholder for merged types. We need to - // do something more real than this. - if (TYPE_ARRAY_ELEMENT (source_type) == object_type_node) - return; - source_type = build_java_array_type (TYPE_ARRAY_ELEMENT (source_type), -1); + assertions_htab = htab_create_ggc (7, type_assertion_hash, + type_assertion_eq, NULL); + TYPE_ASSERTIONS (current_class) = assertions_htab; } - if (TYPE_ARRAY_P (target_type)) - target_type = build_java_array_type (TYPE_ARRAY_ELEMENT (target_type), -1); - if (target_type == object_type_node) - return; + as.assertion_code = assertion_code; + as.op1 = op1; + as.op2 = op2; - if (source_type == target_type) - return; + as_pp = htab_find_slot (assertions_htab, &as, true); - // FIXME: This is just a placeholder for merged types. We need to - // do something more real than this. - if (source_type == object_type_node) + /* Don't add the same assertion twice. */ + if (*as_pp) return; - if (! verify_method) - { - arg = build_decl (PARM_DECL, get_identifier ("classLoader"), ptr_type_node); - DECL_CONTEXT (arg) = verify_method; - DECL_ARG_TYPE (arg) = ptr_type_node; - verify_method - = build_decl (FUNCTION_DECL, verify_identifier_node, - build_function_type (ptr_type_node, end_params_node)); - DECL_ARGUMENTS (verify_method) = arg; - DECL_ARTIFICIAL (verify_method) = 1; - TREE_PUBLIC (verify_method) = 0; - DECL_EXTERNAL (verify_method) = 0; - TREE_PRIVATE (verify_method) = 1; - TREE_STATIC (verify_method) = 1; - TYPE_VERIFY_METHOD (output_class) = verify_method; - build_result_decl (verify_method); - DECL_INITIAL (verify_method) = build (BLOCK, void_type_node); - DECL_CONTEXT (verify_method) = output_class; - TYPE_ASSERTIONS (output_class) - = htab_create_ggc (42, type_assertion_hash, type_assertion_eq, NULL); - } - - { - /* Don't emit the same type assertion twice. */ - type_assertion as; - void **as_pp; - as.source_type = source_type; - as.target_type = target_type; - as_pp = htab_find_slot (TYPE_ASSERTIONS (output_class), &as, true); - if (*as_pp) - return; - *as_pp = ggc_alloc (sizeof (type_assertion)); - **(type_assertion **)as_pp = as; - } - - { - tree source_ref = build_signature_for_libgcj (source_type); - tree target_ref = build_signature_for_libgcj (target_type); - tree args, expr; - - args = tree_cons (NULL_TREE, source_ref, - build_tree_list (NULL_TREE, target_ref)); - args = chainon (build_tree_list (NULL_TREE, DECL_ARGUMENTS (verify_method)), args); - expr = build (CALL_EXPR, itype, - build_address_of (soft_check_assignment_node), - args, NULL_TREE); - DECL_SAVED_TREE (verify_method) - = add_stmt_to_compound (DECL_SAVED_TREE (verify_method), itype, expr); - } -} - + *as_pp = ggc_alloc (sizeof (type_assertion)); + **(type_assertion **)as_pp = as; +} /* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE. @@ -556,12 +494,13 @@ can_widen_reference_to (tree source_type, tree target_type) However, we could do something more optimal. */ if (! flag_verify_invocations) { - add_type_assertion (source_type, target_type); + add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE, + source_type, target_type); if (!quiet_flag) - warning ("assert: %s is assign compatible with %s", - xstrdup (lang_printable_name (target_type, 0)), - xstrdup (lang_printable_name (source_type, 0))); + warning ("assert: %s is assign compatible with %s", + xstrdup (lang_printable_name (target_type, 0)), + xstrdup (lang_printable_name (source_type, 0))); /* Punt everything to runtime. */ return 1; } diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 6688789d9b0..30ad380af0c 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -330,7 +330,6 @@ enum java_tree_index JTI_CLINIT_IDENTIFIER_NODE, JTI_FINIT_IDENTIFIER_NODE, JTI_INSTINIT_IDENTIFIER_NODE, - JTI_VERIFY_IDENTIFIER_NODE, JTI_VOID_SIGNATURE_NODE, JTI_LENGTH_IDENTIFIER_NODE, JTI_FINALIZE_IDENTIFIER_NODE, @@ -378,6 +377,8 @@ enum java_tree_index JTI_SYMBOL_TYPE, JTI_SYMBOLS_ARRAY_TYPE, JTI_SYMBOLS_ARRAY_PTR_TYPE, + JTI_ASSERTION_ENTRY_TYPE, + JTI_ASSERTION_TABLE_TYPE, JTI_END_PARAMS_NODE, @@ -530,8 +531,6 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; /* FIXME "instinit$" and "finit$" should be merged */ #define instinit_identifier_node \ java_global_trees[JTI_INSTINIT_IDENTIFIER_NODE] /* "instinit$" */ -#define verify_identifier_node \ - java_global_trees[JTI_VERIFY_IDENTIFIER_NODE] /* "__verify" */ #define void_signature_node \ java_global_trees[JTI_VOID_SIGNATURE_NODE] /* "()V" */ #define length_identifier_node \ @@ -622,9 +621,11 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; #define symbols_array_type \ 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] + java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE] +#define assertion_entry_type \ + java_global_trees[JTI_ASSERTION_ENTRY_TYPE] +#define assertion_table_type \ + java_global_trees[JTI_ASSERTION_TABLE_TYPE] #define end_params_node \ java_global_trees[JTI_END_PARAMS_NODE] @@ -1013,10 +1014,20 @@ struct treetreehash_entry GTY(()) tree value; }; +/* These represent the possible assertion_code's that can be emitted in the + type assertion table. */ +enum +{ + JV_ASSERT_END_OF_TABLE = 0, /* Last entry in table. */ + JV_ASSERT_TYPES_COMPATIBLE = 1, /* Operand A is assignable to Operand B. */ + JV_ASSERT_IS_INSTANTIABLE = 2 /* Operand A is an instantiable class. */ +}; + typedef struct type_assertion GTY(()) { - tree source_type; - tree target_type; + int assertion_code; /* 'opcode' for the type of this assertion. */ + tree op1; /* First operand. */ + tree op2; /* Second operand. */ } type_assertion; extern tree java_treetreehash_find (htab_t, tree); @@ -1145,6 +1156,8 @@ struct lang_type GTY(()) markers. */ htab_t GTY ((param_is (struct type_assertion))) type_assertions; + /* Table of type assertions to be evaluated + by the runtime when this class is loaded. */ unsigned pic:1; /* Private Inner Class. */ unsigned poic:1; /* Protected Inner Class. */ @@ -1306,6 +1319,7 @@ extern int alloc_class_constant (tree); extern void init_expr_processing (void); extern void push_super_field (tree, tree); extern void init_class_processing (void); +extern void add_type_assertion (tree, int, tree, tree); extern int can_widen_reference_to (tree, tree); extern int class_depth (tree); extern int verify_jvm_instructions (struct JCF *, const unsigned char *, long); @@ -1371,7 +1385,6 @@ extern tree java_mangle_decl (struct obstack *, tree); extern tree java_mangle_class_field (struct obstack *, tree); extern tree java_mangle_class_field_from_string (struct obstack *, char *); extern tree java_mangle_vtable (struct obstack *, tree); -extern const char *lang_printable_name_wls (tree, int); extern void append_gpp_mangled_name (const char *, int); extern void add_predefined_file (tree); diff --git a/gcc/java/verify-glue.c b/gcc/java/verify-glue.c index 7c55a1f58be..fb213405e43 100644 --- a/gcc/java/verify-glue.c +++ b/gcc/java/verify-glue.c @@ -228,6 +228,25 @@ vfy_get_class_name (vfy_jclass klass) return DECL_NAME (TYPE_NAME (klass)); } +bool +vfy_is_assignable_from (vfy_jclass target, vfy_jclass source) +{ + /* At compile time, for the BC-ABI we assume that reference types are always + compatible. However, a type assertion table entry is emitted so that the + runtime can detect binary-incompatible changes. */ + + /* FIXME: implement real test for old ABI. */ + + /* Any class is always assignable to itself, or java.lang.Object. */ + if (source == target || target == object_type_node) + return true; + + /* Otherwise, a type assertion is required. */ + add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE, source, + target); + return true; +} + char vfy_get_primitive_char (vfy_jclass klass) { @@ -396,13 +415,15 @@ vfy_note_stack_depth (vfy_method *method, int pc, int depth) void vfy_note_stack_type (vfy_method *method, int pc, int slot, vfy_jclass type) { + tree label, vec; + slot += method->max_locals; if (type == object_type_node) type = object_ptr_type_node; - tree label = lookup_label (pc); - tree vec = LABEL_TYPE_STATE (label); + label = lookup_label (pc); + vec = LABEL_TYPE_STATE (label); TREE_VEC_ELT (vec, slot) = type; } @@ -410,11 +431,13 @@ void vfy_note_local_type (vfy_method *method ATTRIBUTE_UNUSED, int pc, int slot, vfy_jclass type) { + tree label, vec; + if (type == object_type_node) type = object_ptr_type_node; - tree label = lookup_label (pc); - tree vec = LABEL_TYPE_STATE (label); + label = lookup_label (pc); + vec = LABEL_TYPE_STATE (label); TREE_VEC_ELT (vec, slot) = type; } diff --git a/gcc/java/verify-impl.c b/gcc/java/verify-impl.c index a4130aa8243..2c402a8c62b 100644 --- a/gcc/java/verify-impl.c +++ b/gcc/java/verify-impl.c @@ -221,7 +221,6 @@ typedef struct verifier_context static GTY(()) verifier_context *vfr; /* Local function declarations. */ -bool is_assignable_from_slow (vfy_jclass target, vfy_jclass source); bool type_initialized (type *t); int ref_count_dimensions (ref_intersection *ref); @@ -388,31 +387,31 @@ merge_refs (ref_intersection *ref1, ref_intersection *ref2) return tail; } -/* See if an object of type OTHER can be assigned to an object of - type *THIS. This might resolve classes in one chain or the other. */ +/* See if an object of type SOURCE can be assigned to an object of + type TARGET. This might resolve classes in one chain or the other. */ static bool -ref_compatible (ref_intersection *ref1, ref_intersection *ref2) +ref_compatible (ref_intersection *target, ref_intersection *source) { - for (; ref1 != NULL; ref1 = ref1->ref_next) + for (; target != NULL; target = target->ref_next) { - ref_intersection *ref2_iter = ref2; + ref_intersection *source_iter = source; - for (; ref2_iter != NULL; ref2_iter = ref2_iter->ref_next) + for (; source_iter != NULL; source_iter = source_iter->ref_next) { /* Avoid resolving if possible. */ - if (! ref1->is_resolved - && ! ref2_iter->is_resolved - && vfy_strings_equal (ref1->data.name, - ref2_iter->data.name)) + if (! target->is_resolved + && ! source_iter->is_resolved + && vfy_strings_equal (target->data.name, + source_iter->data.name)) continue; - if (! ref1->is_resolved) - resolve_ref (ref1); - if (! ref2_iter->is_resolved) - resolve_ref (ref2_iter); + if (! target->is_resolved) + resolve_ref (target); + if (! source_iter->is_resolved) + resolve_ref (source_iter); - if (! is_assignable_from_slow (ref1->data.klass, - ref2_iter->data.klass)) + if (! vfy_is_assignable_from (target->data.klass, + source_iter->data.klass)) return false; } } @@ -527,52 +526,6 @@ get_type_val_for_primtype (vfy_jclass k) return get_type_val_for_signature (vfy_get_primitive_char (k)); } -/* This is like _Jv_IsAssignableFrom, but it works even if SOURCE or - TARGET haven't been prepared. */ -bool -is_assignable_from_slow (vfy_jclass target, vfy_jclass source) -{ - /* First, strip arrays. */ - while (vfy_is_array (target)) - { - /* If target is array, source must be as well. */ - if (! vfy_is_array (source)) - return false; - target = vfy_get_component_type (target); - source = vfy_get_component_type (source); - } - - /* Quick success. */ - if (target == vfy_object_type ()) - return true; - - do - { - int i; - if (source == target) - return true; - - if (vfy_is_primitive (target) || vfy_is_primitive (source)) - return false; - - if (vfy_is_interface (target)) - { - for (i = 0; i < vfy_get_interface_count (source); ++i) - { - /* We use a recursive call because we also need to - check superinterfaces. */ - if (is_assignable_from_slow (target, - vfy_get_interface (source, i))) - return true; - } - } - source = vfy_get_superclass (source); - } - while (source != NULL); - - return false; -} - /* The `type' class is used to represent a single type in the verifier. */ struct type { @@ -782,13 +735,7 @@ types_compatible (type *t, type *k) return false; } - /* Reference types are always compatible for the BC-ABI. We defer this test - till runtime. - FIXME: 1. type assertion generation - 2. implement real test for old ABI ?? */ - - return true; - /* return ref_compatible (t->klass, k->klass); */ + return ref_compatible (t->klass, k->klass); } static bool diff --git a/gcc/java/verify.h b/gcc/java/verify.h index 2670ed3b57e..6657ffc471a 100644 --- a/gcc/java/verify.h +++ b/gcc/java/verify.h @@ -99,6 +99,7 @@ vfy_string vfy_get_pool_string (vfy_constants *pool, int index); vfy_jclass vfy_get_pool_class (vfy_constants *pool, int index); vfy_string vfy_make_string (const char *s, int len); vfy_string vfy_get_class_name (vfy_jclass klass); +bool vfy_is_assignable_from (vfy_jclass target, vfy_jclass source); char vfy_get_primitive_char (vfy_jclass klass); int vfy_get_interface_count (vfy_jclass klass); vfy_jclass vfy_get_interface (vfy_jclass klass, int index); diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 1db52f1e420..c63e91a0601 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,18 @@ +2004-11-05 Bryce McKinlay <mckinlay@redhat.com> + + * link.cc: Include VerifyError.h. + (_Jv_Linker::verify_type_assertions): New. Read and evaluate entries + in the type assertion table. + * include/execution.h (_Jv_CompiledEngine::do_verify): Use + verify_type_assertions. + * include/jvm.h (_Jv_Linker::verify_type_assertions): declare. + * java/lang/Class.h (JV_ASSERT_END_OF_TABLE, + JV_ASSERT_TYPES_COMPATIBLE, JV_ASSERT_IS_INSTANTIABLE): Declare + assertion code values. + (struct _Jv_TypeAssertion): Declare. + (assertion_table): New class field. + (verify): Remove class field. + 2004-11-05 Andrew Haley <aph@redhat.com> * Makefile.am: Move jv_dbtool.java to diff --git a/libjava/include/execution.h b/libjava/include/execution.h index 3f2547555fb..b8f47468fc7 100644 --- a/libjava/include/execution.h +++ b/libjava/include/execution.h @@ -46,11 +46,7 @@ struct _Jv_CompiledEngine : public _Jv_ExecutionEngine static void do_verify (jclass klass) { - if (klass->verify) - { - klass->verify(klass->getClassLoaderInternal()); - klass->verify = NULL; - } + _Jv_Linker::verify_type_assertions (klass); } static _Jv_ResolvedMethod *do_resolve_method (_Jv_Method *, jclass, diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 6b32ffaaef3..4e5be6ee877 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -276,6 +276,7 @@ public: static void wait_for_state(jclass, int); static _Jv_word resolve_pool_entry (jclass, int); static void resolve_field (_Jv_Field *, java::lang::ClassLoader *); + static void verify_type_assertions (jclass); }; /* Type of pointer used as finalizer. */ diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 864895762e6..4e7b9a8ee59 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -141,6 +141,23 @@ struct _Jv_CatchClass _Jv_Utf8Const *classname; }; +// Possible values for the assertion_code field in the type assertion table. +enum +{ + JV_ASSERT_END_OF_TABLE = 0, + JV_ASSERT_TYPES_COMPATIBLE = 1, + JV_ASSERT_IS_INSTANTIABLE = 2 +}; + +// Entry in the type assertion table, used to validate type constraints +// for binary compatibility. +struct _Jv_TypeAssertion +{ + jint assertion_code; + _Jv_Utf8Const *op1; + _Jv_Utf8Const *op2; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -476,8 +493,8 @@ private: jclass arrayclass; // Security Domain to which this class belongs (or null). java::security::ProtectionDomain *protectionDomain; - // Pointer to verify method for this class. - void (*verify)(java::lang::ClassLoader *loader); + // Pointer to the type assertion table for this class. + _Jv_TypeAssertion *assertion_table; // Signers of this class (or null). JArray<jobject> *hack_signers; // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace. diff --git a/libjava/link.cc b/libjava/link.cc index ac9e2dfbba2..e67f63f233d 100644 --- a/libjava/link.cc +++ b/libjava/link.cc @@ -1,4 +1,4 @@ -// resolve.cc - Code for linking and resolving classes and pool entries. +// link.cc - Code for linking and resolving classes and pool entries. /* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation @@ -34,6 +34,7 @@ details. */ #include <java/lang/AbstractMethodError.h> #include <java/lang/NoClassDefFoundError.h> #include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/VerifyError.h> #include <java/lang/VMClassLoader.h> #include <java/lang/reflect/Modifier.h> @@ -1590,6 +1591,66 @@ _Jv_Linker::verify_class (jclass klass) klass->engine->verify(klass); } +// Check the assertions contained in the type assertion table for KLASS. +// This is the equivilent of bytecode verification for native, BC-ABI code. +void +_Jv_Linker::verify_type_assertions (jclass klass) +{ + if (debug_link) + fprintf (stderr, "Evaluating type assertions for %s:\n", + klass->name->chars()); + + if (klass->assertion_table == NULL) + return; + + for (int i = 0;; i++) + { + int assertion_code = klass->assertion_table[i].assertion_code; + _Jv_Utf8Const *op1 = klass->assertion_table[i].op1; + _Jv_Utf8Const *op2 = klass->assertion_table[i].op2; + + if (assertion_code == JV_ASSERT_END_OF_TABLE) + return; + else if (assertion_code == JV_ASSERT_TYPES_COMPATIBLE) + { + if (debug_link) + { + fprintf (stderr, " code=%i, operand A=%s B=%s\n", + assertion_code, op1->chars(), op2->chars()); + } + + // The operands are class signatures. op1 is the source, + // op2 is the target. + jclass cl1 = _Jv_FindClassFromSignature (op1->chars(), + klass->getClassLoaderInternal()); + jclass cl2 = _Jv_FindClassFromSignature (op2->chars(), + klass->getClassLoaderInternal()); + + // If the class doesn't exist, ignore the assertion. An exception + // will be thrown later if an attempt is made to actually + // instantiate the class. + if (cl1 == NULL || cl2 == NULL) + continue; + + if (! _Jv_IsAssignableFromSlow (cl2, cl1)) + { + jstring s = JvNewStringUTF ("Incompatible types: In class "); + s = s->concat (klass->getName()); + s = s->concat (JvNewStringUTF (": ")); + s = s->concat (cl1->getName()); + s = s->concat (JvNewStringUTF (" is not assignable to ")); + s = s->concat (cl2->getName()); + throw new java::lang::VerifyError (s); + } + } + else if (assertion_code == JV_ASSERT_IS_INSTANTIABLE) + { + // TODO: Implement this. + } + // Unknown assertion codes are ignored, for forwards-compatibility. + } +} + // FIXME: mention invariants and stuff. void _Jv_Linker::wait_for_state (jclass klass, int state) |