diff options
author | Tom Tromey <tromey@cygnus.com> | 2000-04-28 00:21:06 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2000-04-28 00:21:06 +0000 |
commit | e815887f4d7e3aaa8e68584729c18c9b3c5fef05 (patch) | |
tree | 8b68598e702242c042747ef9d9b00aed4e7d7ab0 /gcc/java/expr.c | |
parent | db6a1df0e0f18a86827e97092fa1293adcc2e89e (diff) | |
download | gcc-e815887f4d7e3aaa8e68584729c18c9b3c5fef05.zip gcc-e815887f4d7e3aaa8e68584729c18c9b3c5fef05.tar.gz gcc-e815887f4d7e3aaa8e68584729c18c9b3c5fef05.tar.bz2 |
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
Diffstat (limited to 'gcc/java/expr.c')
-rw-r--r-- | gcc/java/expr.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/gcc/java/expr.c b/gcc/java/expr.c index c5fe669..5666502 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -1719,6 +1719,7 @@ expand_invoke (opcode, method_ref_index, nargs) (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 @@ expand_invoke (opcode, method_ref_index, nargs) 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 @@ expand_invoke (opcode, method_ref_index, nargs) 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 |