Null pointer check elimination
David Daney
ddaney@avtrex.com
Sat Nov 12 05:53:00 GMT 2005
Thanks Anthony. This has been bothering me for quite some time.
Anthony Green wrote:
> Our compiler inlines many null pointer tests because the language
> requires that we throw NullPointerExeceptions in certain cases that can
> only be detected through explicit tests.
>> What's frustrating is that there are many cases where we're testing the
> nullness of a function return value that we know can never be null. For
> instance, the result of string appends can never be null. Neither can
> object allocations.
See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24242
>> The attached experimental patch detects one special instance of a
> non-null function result (gnu.gcj.runtime.StringBuffer.append()), and
> marks it as being non-null. GCC's value range propagation code then
> magically eliminates any redundant null pointer checks.
I think all methods returning a reference in
gnu.gcj.runtime.StringBuffer, java.lang.StringBuffer,
java.lang.StringBuilder fall into this category.
>> Eventually we should manually mark certain function DECLs as
> not-returning-null instead of my kludgy test for this one case. I don't
> know if/when I can get to that. Perhaps somebody else can take it from
> here.
Looks like all the bits in struct tree_common are used up.
Q: Would it make sense to add a flag to struct tree_decl_common to
indicate !zero, set it using an attribute, (and automatically in the
java front-end for the cases above), and then test for it in tree-vrp.c
similar to below?
>> In any case, here's a patch Diego and I came up with. It will eliminate
> null-pointer checks related to the string concatenation operator (foo =
> "blah" + bar).
>> (Thanks Diego!)
>> AG
>>>>> ------------------------------------------------------------------------
>> Index: tree-vrp.c
> ===================================================================
> --- tree-vrp.c (revision 106799)
> +++ tree-vrp.c (working copy)
> @@ -2216,6 +2216,42 @@ infer_value_range (tree stmt, tree op, e
> if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
> return false;
>> + /* Is this a function call that is guaranteed not to
> + return null? */
> + if (TREE_CODE (stmt) == MODIFY_EXPR
> + && op == TREE_OPERAND (stmt, 0)
> + && TREE_CODE (TREE_TYPE (stmt)) == POINTER_TYPE
> + && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
> + {
> + /* Ok, we know we have an assignment from a function
> + call returning a pointer. Now - for testing purposes
> + - I'm just going to hard-code a test for a specific
> + java method known not to return null. */
> +
> + tree node = TREE_TYPE (TREE_TYPE (stmt));
> + if (TREE_CODE (node) == RECORD_TYPE
> + && TYPE_NAME (node)
> + && TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
> + && DECL_NAME (TYPE_NAME (node))
> + && strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
> + "gnu.gcj.runtime.StringBuffer") == 0)
> + {
> + tree function =
> + TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (stmt, 1), 0), 0);
> +
> + if (TREE_CODE (function) == FUNCTION_DECL
> + && DECL_NAME (function)
> + && strcmp (IDENTIFIER_POINTER (DECL_NAME (function)),
> + "append") == 0)
> + {
> + puts ("WOOHOO!");
> + *val_p = build_int_cst (TREE_TYPE (op), 0);
> + *comp_code_p = NE_EXPR;
> + return true;
> + }
> + }
> + }
> +
> /* Similarly, don't infer anything from statements that may throw
> exceptions. */
> if (tree_could_throw_p (stmt))
> @@ -2734,6 +2770,28 @@ find_assert_locations (basic_block bb)
> }
> }
>> + /* Some assignments may compute values that guarantee certain
> + known ranges to their LHS. */
> + FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_DEF)
> + {
> + tree value;
> + enum tree_code comp_code;
> +
> + /* If OP is used only once, namely in this STMT, don't
> + bother creating an ASSERT_EXPR for it. */
> + if (has_single_use (op))
> + continue;
> +
> + /* If OP is used in such a way that we can infer a value
> + range for it, and we don't find a previous assertion for
> + it, create a new assertion location node for OP. */
> + if (infer_value_range (stmt, op, &comp_code, &value))
> + {
> + register_new_assert_for (op, comp_code, value, bb, NULL, si);
> + need_assert = true;
> + }
> + }
> +
> /* Remember the last statement of the block. */
> last = stmt;
> }
More information about the Java
mailing list