This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Java: Check null pointers


This patch generates null pointer checks inline rather than assuming
that we have an MMU to signal memory faults when they happen.  The
most obvious use for this is a processor that doesn't have an MMU, but
this also allows us to port more easily to new processors, and we
won't need to depend on -fasynchronous-exceptions or
-fsjlj-exceptions.  This isn't adequate on its own because much of
libgcj is written in C++, so we'll need a similar patch for that
language.

This is a work in progress and I intend to change it over time, but as
this patch works with no regressions and is useful on its own I want
to put it into the trunk now.

Andrew.

2001-02-07  Andrew Haley  <aph@redhat.com>

	* expr.c (build_java_indirect_ref): New function.
	(build_java_array_length_access): Use build_java_indirect_ref to
	check for null references.
	(build_java_arrayaccess): Likewise.
	(build_get_class): Likewise.
	(build_field_ref): Likewise.
	(invoke_build_dtable): Likewise.
	(build_invokeinterface): Likewise.

	* lang.c (lang_f_options): Add flag_check_references.

	* jvspec.c (jvgenmain_spec): Add flag_check_references.

	* java-tree.h (flag_check_references): New variable.
	* lang.c (flag_check_references): Likewise.

Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.103
diff -c -2 -p -r1.103 expr.c
*** expr.c	2001/02/16 22:31:52	1.103
--- expr.c	2001/03/22 16:19:55
*************** build_java_array_length_access (node)
*** 711,744 ****
    if (length >= 0)
      return build_int_2 (length, 0);
! 
!   return fold (build1 (INDIRECT_REF,
! 		       int_type_node,
  		       fold (build (PLUS_EXPR, ptr_type_node,
! 				    node, 
  				    JAVA_ARRAY_LENGTH_OFFSET(node)))));
  }
  
! /* Optionally checks an array against the NULL pointer, eventually throwing a
!    NullPointerException. It could replace signal handling, but tied to NULL.
!    ARG1: the pointer to check, ARG2: the expression to use if
!    the pointer is non-null and ARG3 the type that should be returned.   */
  
  tree
! build_java_arraynull_check (node, expr, type)
!     tree node ATTRIBUTE_UNUSED;
!     tree expr;
!     tree type ATTRIBUTE_UNUSED;
  {
! #if 0
!   static int java_array_access_throws_null_exception = 0;
!   node = ???;
!   if (java_array_access_throws_null_exception)
!       return (build (COND_EXPR, 
! 		     type,
! 		     build (EQ_EXPR, int_type_node, node, null_pointer_node),
! 		     build_java_athrow (node), expr ));
!   else
! #endif
!       return (expr);
  }
  
--- 711,755 ----
    if (length >= 0)
      return build_int_2 (length, 0);
!   return fold (build1 (INDIRECT_REF, int_type_node,
  		       fold (build (PLUS_EXPR, ptr_type_node,
! 				    java_check_reference (node, 1), 
  				    JAVA_ARRAY_LENGTH_OFFSET(node)))));
  }
+ 
+ /* Optionally checks a reference against the NULL pointer.  ARG1: the
+    type, ARG2: the expression to use if the pointer is non-null.
+    ARG3: we should check the reference.  Don't generate extra checks
+    if we're not generating code.  */
+ 
+ tree 
+ java_check_reference (expr, check)
+      tree expr;
+      int check;
+ {
+   if (!flag_syntax_only && check)
+     {
+       tree cond;
+       expr = save_expr (expr);
+       cond = build (COND_EXPR, void_type_node,
+ 		    build (EQ_EXPR, boolean_type_node, expr, null_pointer_node),
+ 		    build (CALL_EXPR, void_type_node, 
+ 			   build_address_of (soft_nullpointer_node),
+ 			   NULL_TREE, NULL_TREE),
+ 		    empty_stmt_node);
+       expr = build (COMPOUND_EXPR, TREE_TYPE (expr), cond, expr);
+     }
+ 
+   return expr;
+ }
  
! /* Reference an object: just like an INDIRECT_REF, but with checking.  */
  
  tree
! build_java_indirect_ref (type, expr, check)
!      tree type;
!      tree expr;
!      int check;
  {
!   return build1 (INDIRECT_REF, type, java_check_reference (expr, check));
  }
  
*************** build_java_arrayaccess (array, type, ind
*** 793,805 ****
  	}
      }
! 
    node = build1 (INDIRECT_REF, type, 
  		 fold (build (PLUS_EXPR, ptr_type_node, 
! 			      array, 
  			      (throw ? build (COMPOUND_EXPR, int_type_node, 
  					      throw, arith )
  			             : arith))));
! 
!   return (fold (build_java_arraynull_check (array, node, type)));
  }
  
--- 804,816 ----
  	}
      }
!   
    node = build1 (INDIRECT_REF, type, 
  		 fold (build (PLUS_EXPR, ptr_type_node, 
! 			      java_check_reference (array, flag_check_references), 
  			      (throw ? build (COMPOUND_EXPR, int_type_node, 
  					      throw, arith )
  			             : arith))));
!   
!   return node;
  }
  
*************** expand_java_array_length ()
*** 1009,1013 ****
    tree length = build_java_array_length_access (array);
  
!   push_value (build_java_arraynull_check (array, length, int_type_node));
  }
  
--- 1020,1024 ----
    tree length = build_java_array_length_access (array);
  
!   push_value (length);
  }
  
*************** build_get_class (value)
*** 1119,1123 ****
  		build1 (INDIRECT_REF, dtable_type,
  			build (COMPONENT_REF, dtable_ptr_type,
! 			       build1 (INDIRECT_REF, object_type_node, value),
  			       vtable_field)),
  		class_field);
--- 1130,1135 ----
  		build1 (INDIRECT_REF, dtable_type,
  			build (COMPONENT_REF, dtable_ptr_type,
! 			       build_java_indirect_ref (object_type_node, value,
! 							flag_check_references),
  			       vtable_field)),
  		class_field);
*************** build_field_ref (self_value, self_class,
*** 1486,1491 ****
        self_value = unhand_expr (self_value);
  #endif
!       self_value = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (self_value)),
! 			   self_value);
        return fold (build (COMPONENT_REF, TREE_TYPE (field_decl),
  			  self_value, field_decl));
--- 1498,1503 ----
        self_value = unhand_expr (self_value);
  #endif
!       self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
! 					    self_value, flag_check_references);
        return fold (build (COMPONENT_REF, TREE_TYPE (field_decl),
  			  self_value, field_decl));
*************** invoke_build_dtable (is_invoke_interface
*** 1781,1785 ****
    if (dtable_ident == NULL_TREE)
      dtable_ident = get_identifier ("vtable");
!   dtable = build1 (INDIRECT_REF, object_type_node, objectref );
    dtable = build (COMPONENT_REF, dtable_ptr_type, dtable,
  		  lookup_field (&object_type_node, dtable_ident));
--- 1793,1798 ----
    if (dtable_ident == NULL_TREE)
      dtable_ident = get_identifier ("vtable");
!   dtable = build_java_indirect_ref (object_type_node, objectref, 
! 				    flag_check_references);
    dtable = build (COMPONENT_REF, dtable_ptr_type, dtable,
  		  lookup_field (&object_type_node, dtable_ident));
*************** build_invokeinterface (dtable, method)
*** 1830,1834 ****
      }
  
!   dtable = build1 (INDIRECT_REF, dtable_type, dtable);
    dtable = build (COMPONENT_REF, class_ptr_type, dtable,
  		  lookup_field (&dtable_type, class_ident));
--- 1843,1847 ----
      }
  
!   dtable = build_java_indirect_ref (dtable_type, dtable, flag_check_references);
    dtable = build (COMPONENT_REF, class_ptr_type, dtable,
  		  lookup_field (&dtable_type, class_ident));
*************** expand_invoke (opcode, method_ref_index,
*** 1876,1880 ****
      = 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))
--- 1889,1893 ----
      = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
    tree call, func, method, arg_list, method_type;
!   tree check = NULL_TREE;
  
    if (! CLASS_LOADED_P (self_type))
*************** expand_invoke (opcode, method_ref_index,
*** 1958,1962 ****
        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);
--- 1971,1975 ----
        tree save_arg = save_expr (TREE_VALUE (arg_list));
        TREE_VALUE (arg_list) = save_arg;
!       check = java_check_reference (save_arg, 1);
        func = build_known_method_ref (method, method_type, self_type,
  				     method_signature, arg_list);
*************** expand_invoke (opcode, method_ref_index,
*** 1975,1992 ****
    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;
      }
--- 1988,1994 ----
    TREE_SIDE_EFFECTS (call) = 1;
  
!   if (check != NULL_TREE)
      {
!       call = build (COMPOUND_EXPR, TREE_TYPE (call), check, call);
        TREE_SIDE_EFFECTS (call) = 1;
      }
*************** java_lang_expand_expr (exp, target, tmod
*** 2429,2434 ****
  	  }
  	expand_assignment (build (COMPONENT_REF, TREE_TYPE (data_fld),
! 				  build1 (INDIRECT_REF, array_type, 
! 					  array_decl), data_fld), init, 0, 0);
  	return tmp;
        }
--- 2431,2437 ----
  	  }
  	expand_assignment (build (COMPONENT_REF, TREE_TYPE (data_fld),
! 				  build_java_indirect_ref (array_type, 
! 					  array_decl, flag_check_references), 
! 				  data_fld), init, 0, 0);
  	return tmp;
        }
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.103
diff -c -2 -p -r1.103 java-tree.h
*** java-tree.h	2001/03/19 21:57:36	1.103
--- java-tree.h	2001/03/22 16:19:56
*************** extern int flag_use_boehm_gc;
*** 182,185 ****
--- 182,188 ----
  extern int flag_hash_synchronization;
  
+ /* When non zero, generate checks for references to NULL.  */
+ extern int flag_check_references;
+ 
  /* Encoding used for source files.  */
  extern const char *current_encoding;
*************** extern tree build_new_array PARAMS ((tre
*** 1011,1014 ****
--- 1014,1019 ----
  extern tree build_java_array_length_access PARAMS ((tree));
  extern tree build_java_arraynull_check PARAMS ((tree, tree, tree));
+ extern tree build_java_indirect_ref PARAMS ((tree, tree, int));
+ extern tree java_check_reference PARAMS ((tree, int));
  extern tree build_get_class PARAMS ((tree));
  extern tree build_instanceof PARAMS ((tree, tree));
Index: jvspec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jvspec.c,v
retrieving revision 1.38
diff -c -2 -p -r1.38 jvspec.c
*** jvspec.c	2001/03/19 16:41:59	1.38
--- jvspec.c	2001/03/22 16:19:56
*************** const char jvgenmain_spec[] =
*** 64,67 ****
--- 64,68 ----
  		   %{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
  		   %{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\
+ 		   %{<fcheck-references} %{<fno-check-references}\
  		   %{f*} -fdollars-in-identifiers\
  		   %{aux-info*}\
Index: lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.60
diff -c -2 -p -r1.60 lang.c
*** lang.c	2001/02/24 03:28:39	1.60
--- lang.c	2001/03/22 16:19:57
*************** int flag_jni = 0;
*** 139,142 ****
--- 139,145 ----
  int flag_newer = 1;
  
+ /* When non zero, generate checks for references to NULL.  */
+ int flag_check_references = 0;
+ 
  /* The encoding of the source file.  */
  const char *current_encoding = NULL;
*************** lang_f_options[] =
*** 165,169 ****
    {"use-boehm-gc", &flag_use_boehm_gc, 1},
    {"hash-synchronization", &flag_hash_synchronization, 1},
!   {"jni", &flag_jni, 1}
  };
  
--- 168,173 ----
    {"use-boehm-gc", &flag_use_boehm_gc, 1},
    {"hash-synchronization", &flag_hash_synchronization, 1},
!   {"jni", &flag_jni, 1},
!   {"check-references", &flag_check_references, 1},
  };
  
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.263
diff -c -2 -p -r1.263 parse.y
*** parse.y	2001/03/19 21:57:36	1.263
--- parse.y	2001/03/22 16:20:02
*************** static void java_complete_expand_class P
*** 272,276 ****
  static void java_complete_expand_methods PARAMS ((tree));
  static tree cut_identifier_in_qualified PARAMS ((tree));
- static tree java_stabilize_reference PARAMS ((tree));
  static tree do_unary_numeric_promotion PARAMS ((tree));
  static char * operator_string PARAMS ((tree));
--- 272,275 ----
*************** resolve_field_access (qual_wfl, field_de
*** 8919,8924 ****
      {
        tree length = build_java_array_length_access (where_found);
!       field_ref =
! 	build_java_arraynull_check (type_found, length, int_type_node);
  
        /* In case we're dealing with a static array, we need to
--- 8918,8922 ----
      {
        tree length = build_java_array_length_access (where_found);
!       field_ref = length;
  
        /* In case we're dealing with a static array, we need to
*************** patch_invoke (patch, method, args)
*** 10193,10197 ****
    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
--- 10191,10195 ----
    tree dtable, func;
    tree original_call, t, ta;
!   tree check = NULL_TREE;
  
    /* Last step for args: convert build-in types. If we're dealing with
*************** patch_invoke (patch, method, args)
*** 10232,10241 ****
  	  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.  */
--- 10230,10238 ----
  	  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;
! 	      check = java_check_reference (save_arg, 1);
  	    }
  	  /* Fall through.  */
*************** patch_invoke (patch, method, args)
*** 10297,10316 ****
      }
  
!   /* 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;
      }
--- 10294,10302 ----
      }
  
!   /* If CHECK is set, then we are building a check to see if the object
       is NULL.  */
!   if (check != NULL_TREE)
      {
!       patch = build (COMPOUND_EXPR, TREE_TYPE (patch), check, patch);
        TREE_SIDE_EFFECTS (patch) = 1;
      }
*************** patch_assignment (node, wfl_op1, wfl_op2
*** 12522,12534 ****
        tree base = lvalue;
  
!       /* We need to retrieve the right argument for _Jv_CheckArrayStore */
        if (TREE_CODE (lvalue) == COMPOUND_EXPR)
  	base = TREE_OPERAND (lvalue, 0);
        else
  	{
  	  if (flag_bounds_check)
! 	    base = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (base, 0), 1), 0);
! 	  else
! 	    base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
  	}
  
--- 12508,12525 ----
        tree base = lvalue;
  
!       /* We need to retrieve the right argument for
!          _Jv_CheckArrayStore.  This is somewhat complicated by bounds
!          and null pointer checks, both of which wrap the operand in
!          one layer of COMPOUND_EXPR.  */
        if (TREE_CODE (lvalue) == COMPOUND_EXPR)
  	base = TREE_OPERAND (lvalue, 0);
        else
  	{
+ 	  base = TREE_OPERAND (base, 0);
  	  if (flag_bounds_check)
! 	    base = TREE_OPERAND (base, 1);
! 	  if (flag_check_references)
! 	    base = TREE_OPERAND (base, 1);
! 	  base = TREE_OPERAND (base, 0);	
  	}
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]