Patch: null `this' -vs- final methods
Tom Tromey
tromey@cygnus.com
Thu Apr 27 17:19:00 GMT 2000
I'm checking in this patch, which Alex approved offline. It is the
final version of my patch which changes gcj to correctly handle
invocation of final methods with a null `this'.
2000-04-27 Tom Tromey <tromey@cygnus.com>
Fix for PR gcj/2:
* expr.c (expand_invoke): Generate check to see if object pointer
is null in nonvirtual invocation case.
* java-tree.h (soft_nullpointer_node): Declare.
* decl.c (soft_nullpointer_node): New global.
(init_decl_processing): Initialize soft_nullpointer_node.
* parse.y (invocation_mode): Return INVOKE_NONVIRTUAL for `final'
or `private' methods.
(patch_invoke): Handle INVOKE_NONVIRTUAL case.
Tom
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/decl.c,v
retrieving revision 1.60
diff -u -r1.60 decl.c
--- decl.c 2000/04/04 20:40:19 1.60
+++ decl.c 2000/04/24 23:05:24
@@ -375,6 +375,7 @@
tree soft_anewarray_node;
tree soft_multianewarray_node;
tree soft_badarrayindex_node;
+tree soft_nullpointer_node;
tree throw_node [2];
tree soft_checkarraystore_node;
tree soft_monitorenter_node;
@@ -812,6 +848,15 @@
effects. */
TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1;
TREE_SIDE_EFFECTS (soft_badarrayindex_node) = 1;
+
+ soft_nullpointer_node
+ = builtin_function ("_Jv_ThrowNullPointerException",
+ build_function_type (void_type_node, endlink),
+ 0, NOT_BUILT_IN, NULL_PTR);
+ /* Mark soft_nullpointer_node as a `noreturn' function with side
+ effects. */
+ TREE_THIS_VOLATILE (soft_nullpointer_node) = 1;
+ TREE_SIDE_EFFECTS (soft_nullpointer_node) = 1;
t = tree_cons (NULL_TREE, class_ptr_type,
tree_cons (NULL_TREE, object_ptr_type_node, endlink));
Index: expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/expr.c,v
retrieving revision 1.70
diff -u -r1.70 expr.c
--- expr.c 2000/03/30 23:41:57 1.70
+++ expr.c 2000/04/24 23:05:32
@@ -1719,6 +1719,7 @@
(current_jcf, COMPONENT_REF_CLASS_INDEX(¤t_jcf->cpool, method_ref_index));
const char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
tree call, func, method, arg_list, method_type;
+ tree cond = NULL_TREE;
if (! CLASS_LOADED_P (self_type))
{
@@ -1781,13 +1782,29 @@
flush_quick_stack ();
func = NULL_TREE;
- if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial
- || (opcode == OPCODE_invokevirtual
- && (METHOD_PRIVATE (method)
- || METHOD_FINAL (method)
- || CLASS_FINAL (TYPE_NAME (self_type)))))
+ if (opcode == OPCODE_invokestatic)
func = build_known_method_ref (method, method_type, self_type,
method_signature, arg_list);
+ else if (opcode == OPCODE_invokespecial
+ || (opcode == OPCODE_invokevirtual
+ && (METHOD_PRIVATE (method)
+ || METHOD_FINAL (method)
+ || CLASS_FINAL (TYPE_NAME (self_type)))))
+ {
+ /* If the object for the method call is null, we throw an
+ exception. We don't do this if the object is the current
+ method's `this'. In other cases we just rely on an
+ optimization pass to eliminate redundant checks. FIXME:
+ Unfortunately there doesn't seem to be a way to determine
+ what the current method is right now. */
+ /* We use a SAVE_EXPR here to make sure we only evaluate
+ the new `self' expression once. */
+ tree save_arg = save_expr (TREE_VALUE (arg_list));
+ TREE_VALUE (arg_list) = save_arg;
+ cond = build (EQ_EXPR, boolean_type_node, save_arg, null_pointer_node);
+ func = build_known_method_ref (method, method_type, self_type,
+ method_signature, arg_list);
+ }
else
{
tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface,
@@ -1801,6 +1818,23 @@
call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
+ if (cond != NULL_TREE)
+ {
+ /* We have to make the `then' branch a compound expression to
+ make the types turn out right. This seems bizarre. */
+ call = build (COND_EXPR, TREE_TYPE (call), cond,
+ build (COMPOUND_EXPR, TREE_TYPE (call),
+ build (CALL_EXPR, void_type_node,
+ build_address_of (soft_nullpointer_node),
+ NULL_TREE, NULL_TREE),
+ (FLOAT_TYPE_P (TREE_TYPE (call))
+ ? build_real (TREE_TYPE (call), dconst0)
+ : build1 (CONVERT_EXPR, TREE_TYPE (call),
+ integer_zero_node))),
+ call);
+ TREE_SIDE_EFFECTS (call) = 1;
+ }
+
if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
expand_expr_stmt (call);
else
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/java-tree.h,v
retrieving revision 1.64
diff -u -r1.64 java-tree.h
--- java-tree.h 2000/04/05 23:57:18 1.64
+++ java-tree.h 2000/04/24 23:05:36
@@ -290,6 +298,7 @@
extern tree soft_anewarray_node;
extern tree soft_multianewarray_node;
extern tree soft_badarrayindex_node;
+extern tree soft_nullpointer_node;
extern tree throw_node[];
extern tree soft_checkarraystore_node;
extern tree soft_monitorenter_node;
Index: parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse.y,v
retrieving revision 1.154
diff -u -r1.154 parse.y
--- parse.y 2000/04/21 23:03:19 1.154
+++ parse.y 2000/04/24 23:07:04
@@ -9675,10 +9675,11 @@
{
tree dtable, func;
tree original_call, t, ta;
+ tree cond = NULL_TREE;
/* Last step for args: convert build-in types. If we're dealing with
a new TYPE() type call, the first argument to the constructor
- isn't found in the incomming argument list, but delivered by
+ isn't found in the incoming argument list, but delivered by
`new' */
t = TYPE_ARG_TYPES (TREE_TYPE (method));
if (TREE_CODE (patch) == NEW_CLASS_EXPR)
@@ -9706,6 +9707,22 @@
func = build_invokevirtual (dtable, method);
break;
+ case INVOKE_NONVIRTUAL:
+ /* If the object for the method call is null, we throw an
+ exception. We don't do this if the object is the current
+ method's `this'. In other cases we just rely on an
+ optimization pass to eliminate redundant checks. */
+ if (TREE_VALUE (args) != current_this)
+ {
+ /* We use a SAVE_EXPR here to make sure we only evaluate
+ the new `self' expression once. */
+ tree save_arg = save_expr (TREE_VALUE (args));
+ TREE_VALUE (args) = save_arg;
+ cond = build (EQ_EXPR, boolean_type_node, save_arg,
+ null_pointer_node);
+ }
+ /* Fall through. */
+
case INVOKE_SUPER:
case INVOKE_STATIC:
func = build_known_method_ref (method, TREE_TYPE (method),
@@ -9731,7 +9748,7 @@
TREE_OPERAND (patch, 1) = args;
original_call = patch;
- /* We're processing a `new TYPE ()' form. New is called an its
+ /* We're processing a `new TYPE ()' form. New is called and its
returned value is the first argument to the constructor. We build
a COMPOUND_EXPR and use saved expression so that the overall NEW
expression value is a pointer to a newly created and initialized
@@ -9761,6 +9778,26 @@
TREE_SET_CODE (original_call, CALL_EXPR);
patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new);
}
+
+ /* If COND is set, then we are building a check to see if the object
+ is NULL. */
+ if (cond != NULL_TREE)
+ {
+ /* We have to make the `then' branch a compound expression to
+ make the types turn out right. This seems bizarre. */
+ patch = build (COND_EXPR, TREE_TYPE (patch), cond,
+ build (COMPOUND_EXPR, TREE_TYPE (patch),
+ build (CALL_EXPR, void_type_node,
+ build_address_of (soft_nullpointer_node),
+ NULL_TREE, NULL_TREE),
+ (FLOAT_TYPE_P (TREE_TYPE (patch))
+ ? build_real (TREE_TYPE (patch), dconst0)
+ : build1 (CONVERT_EXPR, TREE_TYPE (patch),
+ integer_zero_node))),
+ patch);
+ TREE_SIDE_EFFECTS (patch) = 1;
+ }
+
return patch;
}
@@ -9774,17 +9811,22 @@
if (super)
return INVOKE_SUPER;
- if (access & ACC_STATIC || access & ACC_FINAL || access & ACC_PRIVATE)
+ if (access & ACC_STATIC)
return INVOKE_STATIC;
- if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
+ /* We have to look for a constructor before we handle nonvirtual
+ calls; otherwise the constructor will look nonvirtual. */
+ if (DECL_CONSTRUCTOR_P (method))
return INVOKE_STATIC;
-
+
+ if (access & ACC_FINAL || access & ACC_PRIVATE)
+ return INVOKE_NONVIRTUAL;
+
+ if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
+ return INVOKE_NONVIRTUAL;
+
if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
return INVOKE_INTERFACE;
-
- if (DECL_CONSTRUCTOR_P (method))
- return INVOKE_STATIC;
return INVOKE_VIRTUAL;
}
More information about the Gcc-patches
mailing list