Patchwork [gccgo] Mark memory which can not contain pointers

login
register
mail settings
Submitter Ian Taylor
Date July 23, 2010, 4:45 p.m.
Message ID <mcrbp9yywo4.fsf@google.com>
Download mbox | patch
Permalink /patch/59820/
State New
Headers show

Comments

Ian Taylor - July 23, 2010, 4:45 p.m.
This patch uses a different allocation routine for memory which can not
contain pointers (e.g., []byte).  The marking already exists in the
memory allocator, this just changes the compiler to use it.  This is in
preparation for garbage collection.  Committed to gccgo branch.

Ian

Patch

diff -r 640e5a4f513f go/expressions.cc
--- a/go/expressions.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/expressions.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -10252,8 +10252,9 @@ 
 {
   tree type_tree = this->type_->get_tree(context->gogo());
   tree size_tree = TYPE_SIZE_UNIT(type_tree);
-  tree space = context->gogo()->allocate_memory(size_tree, this->location());
-  return fold_convert(build_pointer_type (type_tree), space);
+  tree space = context->gogo()->allocate_memory(this->type_, size_tree,
+						this->location());
+  return fold_convert(build_pointer_type(type_tree), space);
 }
 
 // Make an allocation expression.
@@ -11122,7 +11123,8 @@ 
   else
     {
       tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
-      space = context->gogo()->allocate_memory(memsize, this->location());
+      space = context->gogo()->allocate_memory(element_type, memsize,
+					       this->location());
       space = save_expr(space);
 
       tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
@@ -12106,7 +12108,8 @@ 
     return error_mark_node;
   tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
   gcc_assert(TREE_CODE(expr_size) == INTEGER_CST);
-  tree space = context->gogo()->allocate_memory(expr_size, this->location());
+  tree space = context->gogo()->allocate_memory(this->expr_->type(),
+						expr_size, this->location());
   space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space);
   space = save_expr(space);
   tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
diff -r 640e5a4f513f go/gogo-tree.cc
--- a/go/gogo-tree.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/gogo-tree.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -666,6 +666,12 @@ 
 
   // Pass everything back to the middle-end.
 
+  if (this->imported_unsafe_)
+    {
+      // Importing the "unsafe" package automatically disables TBAA.
+      flag_strict_aliasing = false;
+    }
+
   wrapup_global_declarations(vec, count);
 
   cgraph_finalize_compilation_unit();
@@ -918,7 +924,8 @@ 
 	      init = type->get_init_tree(gogo, false);
 	    else
 	      {
-		tree space = gogo->allocate_memory(TYPE_SIZE_UNIT(result_type),
+		tree space = gogo->allocate_memory(type,
+						   TYPE_SIZE_UNIT(result_type),
 						   loc);
 		result_type = build_pointer_type(result_type);
 		tree subinit = type->get_init_tree(gogo, true);
@@ -1265,7 +1272,8 @@ 
   if (is_in_heap)
     {
       tree size = TYPE_SIZE_UNIT(val_type);
-      tree space = gogo->allocate_memory(size, DECL_SOURCE_LOCATION(var_decl));
+      tree space = gogo->allocate_memory(no->var_value()->type(), size,
+					 no->location());
       space = save_expr(space);
       space = fold_convert(build_pointer_type(val_type), space);
       init = build2(COMPOUND_EXPR, TREE_TYPE(space),
@@ -1285,7 +1293,7 @@ 
 // indirection.
 
 tree
-Function::copy_parm_to_heap(Gogo* gogo, tree ref)
+Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref)
 {
   gcc_assert(TREE_CODE(ref) == INDIRECT_REF);
 
@@ -1306,7 +1314,7 @@ 
   DECL_ARG_TYPE(parm_decl) = type;
 
   tree size = TYPE_SIZE_UNIT(type);
-  tree space = gogo->allocate_memory(size, loc);
+  tree space = gogo->allocate_memory(no->var_value()->type(), size, loc);
   space = save_expr(space);
   space = fold_convert(TREE_TYPE(var_decl), space);
   tree init = build2(COMPOUND_EXPR, TREE_TYPE(space),
@@ -1359,7 +1367,7 @@ 
 	    {
 	      // If we take the address of a parameter, then we need
 	      // to copy it into the heap.
-	      tree parm_decl = this->copy_parm_to_heap(gogo, *pp);
+	      tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
 	      gcc_assert(TREE_CODE(*pp) == INDIRECT_REF);
 	      tree var_decl = TREE_OPERAND(*pp, 0);
 	      gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
@@ -1927,19 +1935,36 @@ 
     return NULL_TREE;
 }
 
-// Return a tree which allocates SIZE bytes.
+// Return a tree which allocates SIZE bytes which will holds value of
+// type TYPE.
 
 tree
-Gogo::allocate_memory(tree size, source_location location)
+Gogo::allocate_memory(Type* type, tree size, source_location location)
 {
-  static tree new_fndecl;
-  return Gogo::call_builtin(&new_fndecl,
-			    location,
-			    "__go_new",
-			    1,
-			    ptr_type_node,
-			    sizetype,
-			    size);
+  // If the package imports unsafe, then it may play games with
+  // pointers that look like integers.
+  if (this->imported_unsafe_ || type->has_pointer())
+    {
+      static tree new_fndecl;
+      return Gogo::call_builtin(&new_fndecl,
+				location,
+				"__go_new",
+				1,
+				ptr_type_node,
+				sizetype,
+				size);
+    }
+  else
+    {
+      static tree new_nopointers_fndecl;
+      return Gogo::call_builtin(&new_nopointers_fndecl,
+				location,
+				"__go_new_nopointers",
+				1,
+				ptr_type_node,
+				sizetype,
+				size);
+    }
 }
 
 // Build a builtin struct with a list of fields.  The name is
diff -r 640e5a4f513f go/gogo.cc
--- a/go/gogo.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/gogo.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -27,6 +27,7 @@ 
     functions_(),
     globals_(new Bindings(NULL)),
     imports_(),
+    imported_unsafe_(false),
     packages_(),
     map_descriptors_(NULL),
     type_descriptor_decls_(NULL),
diff -r 640e5a4f513f go/gogo.h
--- a/go/gogo.h	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/gogo.h	Fri Jul 23 09:36:21 2010 -0700
@@ -520,9 +520,10 @@ 
   tree
   interface_method_table_for_type(const Interface_type*, const Named_type*);
 
-  // Return a tree which allocates SIZE bytes.
+  // Return a tree which allocate SIZE bytes to hold values of type
+  // TYPE.
   tree
-  allocate_memory(tree size, source_location);
+  allocate_memory(Type *type, tree size, source_location);
 
   // Return a type to use for pointer to const char.
   static tree
@@ -761,6 +762,8 @@ 
   Bindings* globals_;
   // Mapping from import file names to packages.
   Imports imports_;
+  // Whether the magic unsafe package was imported.
+  bool imported_unsafe_;
   // Mapping from package names we have seen to packages.  This does
   // not include the package we are compiling.
   Packages packages_;
@@ -1084,7 +1087,7 @@ 
   make_receiver_parm_decl(Gogo*, Named_object*, tree);
 
   tree
-  copy_parm_to_heap(Gogo*, tree);
+  copy_parm_to_heap(Gogo*, Named_object*, tree);
 
   void
   build_defer_wrapper(Gogo*, Named_object*, tree, tree*, tree*);
diff -r 640e5a4f513f go/statements.cc
--- a/go/statements.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/statements.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -267,7 +267,8 @@ 
       tree type = TREE_TYPE(decl);
       gcc_assert(POINTER_TYPE_P(type));
       tree size = TYPE_SIZE_UNIT(TREE_TYPE(type));
-      tree space = context->gogo()->allocate_memory(size, this->location());
+      tree space = context->gogo()->allocate_memory(variable->type(), size,
+						    this->location());
       space = fold_convert(TREE_TYPE(decl), space);
       DECL_INITIAL(decl) = space;
       return build2(COMPOUND_EXPR, void_type_node,
diff -r 640e5a4f513f go/types.cc
--- a/go/types.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/types.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -2492,6 +2492,10 @@ 
   { }
 
  protected:
+  bool
+  do_has_pointer() const
+  { gcc_unreachable(); }
+
   tree
   do_get_tree(Gogo*);
 
@@ -2649,6 +2653,24 @@ 
   return true;
 }
 
+// Whether this contains a pointer.
+
+bool
+Struct_type::do_has_pointer() const
+{
+  const Struct_field_list* fields = this->fields();
+  if (fields == NULL)
+    return false;
+  for (Struct_field_list::const_iterator p = fields->begin();
+       p != fields->end();
+       ++p)
+    {
+      if (p->type()->has_pointer())
+	return true;
+    }
+  return false;
+}
+
 // Whether this contains a reference counted component.
 
 bool
@@ -3621,7 +3643,8 @@ 
   tree size_tree = fold_build2_loc(location, MULT_EXPR, TREE_TYPE(count_field),
 				   element_size_tree, capacity_tree);
 
-  tree space = context->gogo()->allocate_memory(size_tree, location);
+  tree space = context->gogo()->allocate_memory(this->element_type_,
+						size_tree, location);
 
   if (value != NULL_TREE)
     space = save_expr(space);
diff -r 640e5a4f513f go/types.h
--- a/go/types.h	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/types.h	Fri Jul 23 09:36:21 2010 -0700
@@ -583,6 +583,13 @@ 
   Type*
   make_non_abstract_type();
 
+  // Return true if this type is or contains a pointer.  This
+  // determines whether the garbage collector needs to look at a value
+  // of this type.
+  bool
+  has_pointer() const
+  { return this->do_has_pointer(); }
+
   // Return true if this type requires reference counting: if copying
   // or destroying a value of this type requires adjusting a reference
   // count.
@@ -888,6 +895,10 @@ 
   { return true; }
 
   virtual bool
+  do_has_pointer() const
+  { return false; }
+
+  virtual bool
   do_is_refcounted() const
   { return false; }
 
@@ -1488,6 +1499,10 @@ 
 
  protected:
   bool
+  do_has_pointer() const
+  { return true; }
+
+  bool
   do_is_refcounted() const
   { return true; }
 
@@ -1600,6 +1615,11 @@ 
   int
   do_traverse(Traverse*);
 
+  // A trampoline function has a pointer which matters for GC.
+  bool
+  do_has_pointer() const
+  { return true; }
+
   // Function types are really pointers, and they are reference
   // counted in case that pointer points to a trampoline.
   bool
@@ -1670,6 +1690,10 @@ 
   do_traverse(Traverse*);
 
   bool
+  do_has_pointer() const
+  { return true; }
+
+  bool
   do_is_refcounted() const
   { return !this->is_unsafe_pointer_type(); }
 
@@ -1922,6 +1946,9 @@ 
   do_verify();
 
   bool
+  do_has_pointer() const;
+
+  bool
   do_has_refcounted_component() const;
 
   void
@@ -2015,6 +2042,12 @@ 
   do_traverse(Traverse* traverse);
 
   bool
+  do_has_pointer() const
+  {
+    return this->length_ == NULL || this->element_type_->has_pointer();
+  }
+
+  bool
   do_is_refcounted() const
   {
     return (this->length_ == NULL
@@ -2108,6 +2141,10 @@ 
   do_verify();
 
   bool
+  do_has_pointer() const
+  { return true; }
+
+  bool
   do_is_refcounted() const
   { return true; }
 
@@ -2189,6 +2226,10 @@ 
   { return Type::traverse(this->element_type_, traverse); }
 
   bool
+  do_has_pointer() const
+  { return true; }
+
+  bool
   do_is_refcounted() const
   { return true; }
 
@@ -2293,6 +2334,10 @@ 
   do_traverse(Traverse*);
 
   bool
+  do_has_pointer() const
+  { return true; }
+
+  bool
   do_is_refcounted() const
   { return true; }
 
@@ -2493,6 +2538,10 @@ 
   do_verify();
 
   bool
+  do_has_pointer() const
+  { return this->type_->has_pointer(); }
+
+  bool
   do_is_refcounted() const
   { return this->type_->is_refcounted(); }
 
@@ -2626,6 +2675,10 @@ 
   do_traverse(Traverse* traverse);
 
   bool
+  do_has_pointer() const
+  { return this->base()->has_pointer(); }
+
+  bool
   do_is_refcounted() const
   { return this->base()->is_refcounted(); }
 
diff -r 640e5a4f513f go/unsafe.cc
--- a/go/unsafe.cc	Fri Jul 23 03:59:55 2010 -0700
+++ b/go/unsafe.cc	Fri Jul 23 09:36:21 2010 -0700
@@ -18,9 +18,6 @@ 
 {
   location_t bloc = BUILTINS_LOCATION;
 
-  // Importing the "unsafe" package automatically disables TBAA.
-  flag_strict_aliasing = false;
-
   bool add_to_globals;
   Package* package = this->add_imported_package("unsafe", local_name,
 						is_local_name_exported,
@@ -132,4 +129,6 @@ 
   no = bindings->add_function_declaration("NewArray", package, fntype, bloc);
   if (add_to_globals)
     this->add_named_object(no);
+
+  this->imported_unsafe_ = true;
 }
diff -r 640e5a4f513f libgo/runtime/go-new.c
--- a/libgo/runtime/go-new.c	Fri Jul 23 03:59:55 2010 -0700
+++ b/libgo/runtime/go-new.c	Fri Jul 23 09:36:21 2010 -0700
@@ -5,13 +5,17 @@ 
    license that can be found in the LICENSE file.  */
 
 #include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
 
 void *
 __go_new (size_t size)
 {
-  void *ret;
+  return __go_alloc (size);
+}
 
-  ret = __go_alloc (size);
-  __builtin_memset (ret, 0, size);
-  return ret;
+void *
+__go_new_nopointers (size_t size)
+{
+  return mallocgc (size, RefNoPointers, 1, 1);
 }