This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: RFC: new verifier integration
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 26 Oct 2004 16:34:05 -0600
- Subject: Patch: RFC: new verifier integration
- Reply-to: tromey at redhat dot com
I'm not checking this in as-is, but I wanted people to be able to try
it out if they wanted.
With this I can successfully use "-fnew-verifier -findirect-dispatch"
to compile .jar files from Eclipse 2 (I've only tried a random subset,
not all of them; but I know they are being used) and run the result.
Andrew, let me know what you think. Most of this is basically ad hoc.
I found I didn't need to add NOP_EXPRs everywhere I thought I would;
at least according to the "doesn't crash gcc, the result still runs"
metric. Perhaps that is short-sighted.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* decl.c (check_local_unnamed_variable): Recognize
promoted-to-int parameters when using the new verifier.
* expr.c (expand_java_arraystore): Explicitly request array type
when using new verifier.
(expand_java_arrayload): Likewise.
(invoke_build_dtable): Don't pass object_type_node as
expression argument to build_java_indirect_ref.
(build_java_check_indexed_type): Do nothing.
(build_java_arraystore_check): Handle case where array doesn't
have array type.
(build_java_array_length_access): Likewise.
(expand_invoke): Handle case where interface overrides a method
from Object.
(pop_type_0): Always succeed for reference types.
(process_jvm_instruction): Don't pop a value in a dead
exception handler.
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.178.4.11
diff -u -r1.178.4.11 decl.c
--- decl.c 12 Oct 2004 12:42:42 -0000 1.178.4.11
+++ decl.c 26 Oct 2004 22:19:03 -0000
@@ -262,7 +262,17 @@
*/
|| (TREE_CODE (decl_type) == POINTER_TYPE
&& TREE_CODE (decl) == PARM_DECL
- && TREE_CODE (type) == POINTER_TYPE))
+ && TREE_CODE (type) == POINTER_TYPE)
+
+ /* The new verifier requires a similar treatment in the
+ situation where the parameter has an integral type which
+ promotes to `int'. */
+ || (flag_new_verifier
+ && TREE_CODE (decl) == PARM_DECL
+ && INTEGRAL_TYPE_P (decl_type)
+ && TYPE_PRECISION (decl_type) <= 32
+ && INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) <= 32))
{
if (best == NULL_TREE
|| (decl_type == type && TREE_TYPE (best) != type))
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.185.2.16
diff -u -r1.185.2.16 expr.c
--- expr.c 25 Oct 2004 19:12:36 -0000 1.185.2.16
+++ expr.c 26 Oct 2004 22:19:04 -0000
@@ -341,20 +341,32 @@
}
if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t)
&& TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32)
- return t;
+ return t;
if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE)
{
- if (type == ptr_type_node || type == object_ptr_type_node)
- return t;
- else if (t == ptr_type_node) /* Special case for null reference. */
- return type;
- /* This is a kludge, but matches what Sun's verifier does.
- It can be tricked, but is safe as long as type errors
- (i.e. interface method calls) are caught at run-time. */
- else if (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (type))))
- return object_ptr_type_node;
- else if (can_widen_reference_to (t, type))
- return t;
+ if (flag_new_verifier)
+ {
+ /* Since the verifier has already run, we know that any
+ types we see will be compatible. In BC mode, this fact
+ may be checked at runtime, but if that is so then we can
+ assume its truth here as well. So, we always succeed
+ here, with the expected type. */
+ return type;
+ }
+ else
+ {
+ if (type == ptr_type_node || type == object_ptr_type_node)
+ return t;
+ else if (t == ptr_type_node) /* Special case for null reference. */
+ return type;
+ /* This is a kludge, but matches what Sun's verifier does.
+ It can be tricked, but is safe as long as type errors
+ (i.e. interface method calls) are caught at run-time. */
+ else if (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (type))))
+ return object_ptr_type_node;
+ else if (can_widen_reference_to (t, type))
+ return t;
+ }
}
if (! flag_verify_invocations && flag_indirect_dispatch
@@ -387,7 +399,7 @@
pop_type (tree type)
{
char *message = NULL;
- type = pop_type_0 (type, &message);
+ type = pop_type_0 (type, &message);
if (message != NULL)
{
error ("%s", message);
@@ -867,13 +879,18 @@
throws a NullPointerException. The only way we could get a node
of type ptr_type_node at this point is `aconst_null; arraylength'
or something equivalent. */
- if (type == ptr_type_node)
+ if (!flag_new_verifier && type == ptr_type_node)
return build3 (CALL_EXPR, int_type_node,
build_address_of (soft_nullpointer_node),
NULL_TREE, NULL_TREE);
if (!is_array_type_p (type))
- abort ();
+ {
+ /* With the new verifier, we will see an ordinary pointer type
+ here. In this case, we just use an arbitrary array type. */
+ array_type = build_java_array_type (object_ptr_type_node, -1);
+ type = promote_type (array_type);
+ }
length = java_array_type_length (type);
if (length >= 0)
@@ -934,6 +951,13 @@
tree ref;
tree array_type = TREE_TYPE (TREE_TYPE (array));
+ if (!is_array_type_p (TREE_TYPE (array)))
+ {
+ /* With the new verifier, we will see an ordinary pointer type
+ here. In this case, we just use the correct array type. */
+ array_type = build_java_array_type (type, -1);
+ }
+
if (flag_bounds_check)
{
/* Generate:
@@ -983,11 +1007,21 @@
tree array_type_p = TREE_TYPE (array);
tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object)));
- if (! is_array_type_p (array_type_p))
- abort ();
+ if (! flag_verify_invocations)
+ {
+ /* With the new verifier, we don't track precise types. FIXME:
+ performance regression here. */
+ element_type = TYPE_NAME (object_type_node);
+ }
+ else
+ {
+ if (! is_array_type_p (array_type_p))
+ abort ();
- /* Get the TYPE_DECL for ARRAY's element type. */
- element_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
+ /* Get the TYPE_DECL for ARRAY's element type. */
+ element_type
+ = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
+ }
if (TREE_CODE (element_type) != TYPE_DECL
|| TREE_CODE (object_type) != TYPE_DECL)
@@ -999,10 +1033,11 @@
/* No check is needed if the element type is final or is itself an array.
Also check that element_type matches object_type, since in the bytecode
compilation case element_type may be the actual element type of the array
- rather than its declared type. */
+ rather than its declared type. However, if we're doing indirect
+ dispatch, we can't do the `final' optimization. */
if (element_type == object_type
&& (TYPE_ARRAY_P (TREE_TYPE (element_type))
- || CLASS_FINAL (element_type)))
+ || (! flag_indirect_dispatch && CLASS_FINAL (element_type))))
return build1 (NOP_EXPR, array_type_p, array);
/* OBJECT might be wrapped by a SAVE_EXPR. */
@@ -1044,24 +1079,30 @@
ARRAY_NODE. This function is used to retrieve something less vague than
a pointer type when indexing the first dimension of something like [[<t>.
May return a corrected type, if necessary, otherwise INDEXED_TYPE is
- return unchanged.
- As a side effect, it also makes sure that ARRAY_NODE is an array. */
+ return unchanged. */
static tree
build_java_check_indexed_type (tree array_node, tree indexed_type)
{
tree elt_type;
+ /* We used to check to see if ARRAY_NODE really had array type.
+ However, with the new verifier, this is not necessary, as we know
+ that the object will be an array of the appropriate type. */
+
+ if (flag_new_verifier)
+ return indexed_type;
+
if (!is_array_type_p (TREE_TYPE (array_node)))
abort ();
elt_type = (TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (array_node))));
- if (indexed_type == ptr_type_node )
- return promote_type (elt_type);
+ if (indexed_type == ptr_type_node)
+ return promote_type (elt_type);
/* BYTE/BOOLEAN store and load are used for both type */
- if (indexed_type == byte_type_node && elt_type == boolean_type_node )
+ if (indexed_type == byte_type_node && elt_type == boolean_type_node)
return boolean_type_node;
if (indexed_type != elt_type )
@@ -1172,7 +1213,22 @@
&& TYPE_PRECISION (rhs_type_node) <= 32) ?
int_type_node : rhs_type_node);
tree index = pop_value (int_type_node);
- tree array = pop_value (ptr_type_node);
+ tree array_type, array;
+
+ if (flag_new_verifier)
+ {
+ /* If we're processing an `aaload' we might as well just pick
+ `Object'. */
+ if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
+ array_type = build_java_array_type (object_ptr_type_node, -1);
+ else
+ array_type = build_java_array_type (rhs_type_node, -1);
+ }
+ else
+ array_type = ptr_type_node;
+ array = pop_value (array_type);
+ if (flag_new_verifier)
+ array = build1 (NOP_EXPR, promote_type (array_type), array);
rhs_type_node = build_java_check_indexed_type (array, rhs_type_node);
@@ -1199,25 +1255,42 @@
*/
static void
-expand_java_arrayload (tree lhs_type_node )
+expand_java_arrayload (tree lhs_type_node)
{
tree load_node;
tree index_node = pop_value (int_type_node);
- tree array_node = pop_value (ptr_type_node);
+ tree array_type;
+ tree array_node;
+
+ if (flag_new_verifier)
+ {
+ /* If we're processing an `aaload' we might as well just pick
+ `Object'. */
+ if (TREE_CODE (lhs_type_node) == POINTER_TYPE)
+ array_type = build_java_array_type (object_ptr_type_node, -1);
+ else
+ array_type = build_java_array_type (lhs_type_node, -1);
+ }
+ else
+ array_type = ptr_type_node;
+ array_node = pop_value (array_type);
+ if (flag_new_verifier)
+ array_node = build1 (NOP_EXPR, promote_type (array_type), array_node);
index_node = save_expr (index_node);
array_node = save_expr (array_node);
-
+
if (TREE_TYPE (array_node) == ptr_type_node)
/* The only way we could get a node of type ptr_type_node at this
- point is `aconst_null; arraylength' or something equivalent, so
- unconditionally throw NullPointerException. */
+ point is `aconst_null; arraylength' or something equivalent, so
+ unconditionally throw NullPointerException. */
load_node = build3 (CALL_EXPR, lhs_type_node,
build_address_of (soft_nullpointer_node),
NULL_TREE, NULL_TREE);
else
{
- lhs_type_node = build_java_check_indexed_type (array_node, lhs_type_node);
+ lhs_type_node = build_java_check_indexed_type (array_node,
+ lhs_type_node);
load_node = build_java_arrayaccess (array_node,
lhs_type_node,
index_node);
@@ -2075,9 +2148,9 @@
argument is an array then get the dispatch table of the class
Object rather than the one from the objectref. */
objectref = (is_invoke_interface
- && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list))) ?
- object_type_node : TREE_VALUE (arg_list));
-
+ && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
+ ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
+
if (dtable_ident == NULL_TREE)
dtable_ident = get_identifier ("vtable");
dtable = build_java_indirect_ref (object_type_node, objectref,
@@ -2238,7 +2311,8 @@
{
tree method_signature
= COMPONENT_REF_SIGNATURE(¤t_jcf->cpool, method_ref_index);
- tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, method_ref_index);
+ tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool,
+ method_ref_index);
tree self_type
= get_class_constant (current_jcf,
COMPONENT_REF_CLASS_INDEX(¤t_jcf->cpool,
@@ -2262,12 +2336,22 @@
else
method = lookup_java_method (self_type, method_name, method_signature);
- /* We've found a method in an interface, but this isn't an interface call. */
+ /* We've found a method in an interface, but this isn't an interface
+ call. */
if (opcode != OPCODE_invokeinterface
&& method
&& (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))))
method = NULL_TREE;
+ /* We've found a non-interface method but we are making an
+ interface call. This can happen if the interface overrides a
+ method in Object. */
+ if (! flag_verify_invocations
+ && opcode == OPCODE_invokeinterface
+ && method
+ && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
+ method = NULL_TREE;
+
if (method == NULL_TREE)
{
if (flag_verify_invocations || ! flag_indirect_dispatch)
@@ -2287,7 +2371,8 @@
flags |= ACC_INTERFACE;
CLASS_INTERFACE (TYPE_NAME (self_type)) = 1;
}
- method = add_method (self_type, flags, method_name, method_signature);
+ method = add_method (self_type, flags, method_name,
+ method_signature);
DECL_ARTIFICIAL (method) = 1;
METHOD_DUMMY (method) = 1;
layout_class_method (self_type, NULL,
@@ -2323,6 +2408,9 @@
if (method == NULL_TREE)
{
+ /* If we got here, we emitted an error message above. So we
+ just pop the arguments, push a properly-typed zero, and
+ continue. */
method_type = get_type_from_signature (method_signature);
pop_arguments (TYPE_ARG_TYPES (method_type));
if (opcode != OPCODE_invokestatic)
@@ -2992,8 +3080,14 @@
replace the top of the stack with the thrown object reference */
if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET)
{
- tree type = pop_type (promote_type (throwable_type_node));
- push_value (build_exception_object_ref (type));
+ /* Note that the new verifier will not emit a type map at all
+ for dead exception handlers. In this case we just ignore
+ the situation. */
+ if (! flag_new_verifier || (instruction_bits[PC] & BCODE_VERIFIED) != 0)
+ {
+ tree type = pop_type (promote_type (throwable_type_node));
+ push_value (build_exception_object_ref (type));
+ }
}
switch (byte_ops[PC++])