This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: Java: [BC] Implement type assertion table
Tom Tromey wrote:
Bryce> Doing the work to lay out indirect-dispatch tables and such is also
Bryce> "linking", but I agree that having the distinction between generic
Bryce> class layout and that which is specific to the BC-ABI may make
Bryce> sense. However, there is already native-code/BC-ABI-specific
Bryce> functions are already in _Jv_Linker - link_symbol_table(),
Bryce> link_exception_table(), etc. We could separate these out into some
Bryce> other class/file, specific to the BC-ABI?
Yeah, good point. Go ahead and put your patch in as is.
Maybe we need another refactoring in here, but there's no need to
hold up this patch waiting for it.
I've checked it with a few small cleanups. The actual patch checked in
follows.
Regards
Bryce
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.
Index: libjava/link.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Attic/link.cc,v
retrieving revision 1.1.2.9
diff -u -r1.1.2.9 link.cc
--- libjava/link.cc 5 Nov 2004 04:30:02 -0000 1.1.2.9
+++ libjava/link.cc 5 Nov 2004 19:27:41 -0000
@@ -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 @@
#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 @@
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)
Index: libjava/include/execution.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/Attic/execution.h,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 execution.h
--- libjava/include/execution.h 18 Oct 2004 23:48:57 -0000 1.1.2.2
+++ libjava/include/execution.h 5 Nov 2004 19:27:41 -0000
@@ -46,11 +46,7 @@
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,
Index: libjava/include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.63.6.9
diff -u -r1.63.6.9 jvm.h
--- libjava/include/jvm.h 5 Nov 2004 04:30:04 -0000 1.63.6.9
+++ libjava/include/jvm.h 5 Nov 2004 19:27:41 -0000
@@ -276,6 +276,7 @@
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. */
Index: libjava/java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.63.12.15
diff -u -r1.63.12.15 Class.h
--- libjava/java/lang/Class.h 12 Oct 2004 14:53:01 -0000 1.63.12.15
+++ libjava/java/lang/Class.h 5 Nov 2004 19:27:41 -0000
@@ -141,6 +141,23 @@
_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 @@
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.
Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.180.2.16
diff -u -r1.180.2.16 class.c
--- gcc/java/class.c 5 Nov 2004 01:49:15 -0000 1.180.2.16
+++ gcc/java/class.c 5 Nov 2004 19:28:33 -0000
@@ -62,6 +62,7 @@
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 @@
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 @@
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 @@
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)
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.178.4.12
diff -u -r1.178.4.12 decl.c
--- gcc/java/decl.c 1 Nov 2004 18:26:50 -0000 1.178.4.12
+++ gcc/java/decl.c 5 Nov 2004 19:28:33 -0000
@@ -735,6 +735,15 @@
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 @@
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 @@
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);
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.185.2.19
diff -u -r1.185.2.19 expr.c
--- gcc/java/expr.c 3 Nov 2004 20:43:44 -0000 1.185.2.19
+++ gcc/java/expr.c 5 Nov 2004 19:28:34 -0000
@@ -416,8 +416,9 @@
{
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 @@
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 @@
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;
}
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.197.2.12
diff -u -r1.197.2.12 java-tree.h
--- gcc/java/java-tree.h 20 Oct 2004 22:56:51 -0000 1.197.2.12
+++ gcc/java/java-tree.h 5 Nov 2004 19:28:34 -0000
@@ -330,7 +330,6 @@
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 @@
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 @@
/* 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 @@
#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 @@
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 @@
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 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_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);
Index: gcc/java/verify-glue.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/verify-glue.c,v
retrieving revision 1.1.2.10
diff -u -r1.1.2.10 verify-glue.c
--- gcc/java/verify-glue.c 26 Oct 2004 22:10:14 -0000 1.1.2.10
+++ gcc/java/verify-glue.c 5 Nov 2004 19:28:34 -0000
@@ -228,6 +228,25 @@
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 @@
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 @@
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;
}
Index: gcc/java/verify-impl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/verify-impl.c,v
retrieving revision 1.1.2.16
diff -u -r1.1.2.16 verify-impl.c
--- gcc/java/verify-impl.c 1 Nov 2004 18:34:35 -0000 1.1.2.16
+++ gcc/java/verify-impl.c 5 Nov 2004 19:28:34 -0000
@@ -221,7 +221,6 @@
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 @@
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 @@
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 @@
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
Index: gcc/java/verify.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/verify.h,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 verify.h
--- gcc/java/verify.h 26 Oct 2004 22:10:14 -0000 1.1.2.7
+++ gcc/java/verify.h 5 Nov 2004 19:28:34 -0000
@@ -99,6 +99,7 @@
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);