aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryce McKinlay <mckinlay@redhat.com>2004-11-05 19:30:12 +0000
committerBryce McKinlay <mckinlay@redhat.com>2004-11-05 19:30:12 +0000
commitfc81ff3a0b10fdc1c8d73677c95726734482d4a4 (patch)
treec7a97f592aa97e90ce9671b2548dac6bc5657b51
parent70b9be8bc1fa69eadb2882e894ee95ef62c3989c (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/ChangeLog36
-rw-r--r--gcc/java/class.c112
-rw-r--r--gcc/java/decl.c12
-rw-r--r--gcc/java/expr.c135
-rw-r--r--gcc/java/java-tree.h31
-rw-r--r--gcc/java/verify-glue.c31
-rw-r--r--gcc/java/verify-impl.c87
-rw-r--r--gcc/java/verify.h1
-rw-r--r--libjava/ChangeLog15
-rw-r--r--libjava/include/execution.h6
-rw-r--r--libjava/include/jvm.h1
-rw-r--r--libjava/java/lang/Class.h21
-rw-r--r--libjava/link.cc63
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)