Commit e815887f by Tom Tromey Committed by Tom Tromey

re GNATS gcj/2 (Method call on null instance should throw NullPointerException)

	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.

From-SVN: r33495
parent db6a1df0
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.
Wed Apr 26 14:29:33 2000 Alexandre Petit-Bianco <apbianco@cygnus.com> Wed Apr 26 14:29:33 2000 Alexandre Petit-Bianco <apbianco@cygnus.com>
* decl.c (complete_start_java_method): Don't call _Jv_InitClass * decl.c (complete_start_java_method): Don't call _Jv_InitClass
......
...@@ -375,6 +375,7 @@ tree soft_newarray_node; ...@@ -375,6 +375,7 @@ tree soft_newarray_node;
tree soft_anewarray_node; tree soft_anewarray_node;
tree soft_multianewarray_node; tree soft_multianewarray_node;
tree soft_badarrayindex_node; tree soft_badarrayindex_node;
tree soft_nullpointer_node;
tree throw_node [2]; tree throw_node [2];
tree soft_checkarraystore_node; tree soft_checkarraystore_node;
tree soft_monitorenter_node; tree soft_monitorenter_node;
...@@ -813,6 +814,15 @@ init_decl_processing () ...@@ -813,6 +814,15 @@ init_decl_processing ()
TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1; TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1;
TREE_SIDE_EFFECTS (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, t = tree_cons (NULL_TREE, class_ptr_type,
tree_cons (NULL_TREE, object_ptr_type_node, endlink)); tree_cons (NULL_TREE, object_ptr_type_node, endlink));
soft_checkcast_node soft_checkcast_node
......
...@@ -1719,6 +1719,7 @@ expand_invoke (opcode, method_ref_index, nargs) ...@@ -1719,6 +1719,7 @@ expand_invoke (opcode, method_ref_index, nargs)
(current_jcf, COMPONENT_REF_CLASS_INDEX(&current_jcf->cpool, method_ref_index)); (current_jcf, COMPONENT_REF_CLASS_INDEX(&current_jcf->cpool, method_ref_index));
const char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type))); const char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
tree call, func, method, arg_list, method_type; tree call, func, method, arg_list, method_type;
tree cond = NULL_TREE;
if (! CLASS_LOADED_P (self_type)) if (! CLASS_LOADED_P (self_type))
{ {
...@@ -1781,13 +1782,29 @@ expand_invoke (opcode, method_ref_index, nargs) ...@@ -1781,13 +1782,29 @@ expand_invoke (opcode, method_ref_index, nargs)
flush_quick_stack (); flush_quick_stack ();
func = NULL_TREE; func = NULL_TREE;
if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial if (opcode == OPCODE_invokestatic)
|| (opcode == OPCODE_invokevirtual
&& (METHOD_PRIVATE (method)
|| METHOD_FINAL (method)
|| CLASS_FINAL (TYPE_NAME (self_type)))))
func = build_known_method_ref (method, method_type, self_type, func = build_known_method_ref (method, method_type, self_type,
method_signature, arg_list); 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 else
{ {
tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface, tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface,
...@@ -1801,6 +1818,23 @@ expand_invoke (opcode, method_ref_index, nargs) ...@@ -1801,6 +1818,23 @@ expand_invoke (opcode, method_ref_index, nargs)
call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE); call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1; 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) if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
expand_expr_stmt (call); expand_expr_stmt (call);
else else
......
...@@ -290,6 +290,7 @@ extern tree soft_newarray_node; ...@@ -290,6 +290,7 @@ extern tree soft_newarray_node;
extern tree soft_anewarray_node; extern tree soft_anewarray_node;
extern tree soft_multianewarray_node; extern tree soft_multianewarray_node;
extern tree soft_badarrayindex_node; extern tree soft_badarrayindex_node;
extern tree soft_nullpointer_node;
extern tree throw_node[]; extern tree throw_node[];
extern tree soft_checkarraystore_node; extern tree soft_checkarraystore_node;
extern tree soft_monitorenter_node; extern tree soft_monitorenter_node;
......
...@@ -9662,10 +9662,11 @@ patch_invoke (patch, method, args) ...@@ -9662,10 +9662,11 @@ patch_invoke (patch, method, args)
{ {
tree dtable, func; tree dtable, func;
tree original_call, t, ta; tree original_call, t, ta;
tree cond = NULL_TREE;
/* Last step for args: convert build-in types. If we're dealing with /* Last step for args: convert build-in types. If we're dealing with
a new TYPE() type call, the first argument to the constructor 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' */ `new' */
t = TYPE_ARG_TYPES (TREE_TYPE (method)); t = TYPE_ARG_TYPES (TREE_TYPE (method));
if (TREE_CODE (patch) == NEW_CLASS_EXPR) if (TREE_CODE (patch) == NEW_CLASS_EXPR)
...@@ -9693,6 +9694,22 @@ patch_invoke (patch, method, args) ...@@ -9693,6 +9694,22 @@ patch_invoke (patch, method, args)
func = build_invokevirtual (dtable, method); func = build_invokevirtual (dtable, method);
break; 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_SUPER:
case INVOKE_STATIC: case INVOKE_STATIC:
func = build_known_method_ref (method, TREE_TYPE (method), func = build_known_method_ref (method, TREE_TYPE (method),
...@@ -9718,7 +9735,7 @@ patch_invoke (patch, method, args) ...@@ -9718,7 +9735,7 @@ patch_invoke (patch, method, args)
TREE_OPERAND (patch, 1) = args; TREE_OPERAND (patch, 1) = args;
original_call = patch; 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 returned value is the first argument to the constructor. We build
a COMPOUND_EXPR and use saved expression so that the overall NEW a COMPOUND_EXPR and use saved expression so that the overall NEW
expression value is a pointer to a newly created and initialized expression value is a pointer to a newly created and initialized
...@@ -9748,6 +9765,26 @@ patch_invoke (patch, method, args) ...@@ -9748,6 +9765,26 @@ patch_invoke (patch, method, args)
TREE_SET_CODE (original_call, CALL_EXPR); TREE_SET_CODE (original_call, CALL_EXPR);
patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new); 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; return patch;
} }
...@@ -9761,17 +9798,22 @@ invocation_mode (method, super) ...@@ -9761,17 +9798,22 @@ invocation_mode (method, super)
if (super) if (super)
return INVOKE_SUPER; return INVOKE_SUPER;
if (access & ACC_STATIC || access & ACC_FINAL || access & ACC_PRIVATE) if (access & ACC_STATIC)
return INVOKE_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; 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)))) if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
return INVOKE_INTERFACE; return INVOKE_INTERFACE;
if (DECL_CONSTRUCTOR_P (method))
return INVOKE_STATIC;
return INVOKE_VIRTUAL; return INVOKE_VIRTUAL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment