This patch by Chris Manghane passes type information to
compiler-generated heap allocations in gccgo.  This gives us precise
type information for much of the gccgo heap, and means that garbage
collection is much more precise and less prone to errors due to
mistaking integer or float values as pointers.  Bootstrapped and ran
Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff -r f6e937cbbe5a go/expressions.cc
--- a/go/expressions.cc Mon Oct 20 11:04:12 2014 -0700
+++ b/go/expressions.cc Mon Oct 20 12:04:16 2014 -0700
@@ -12170,7 +12170,7 @@
   { return this->vals_ == NULL ? 0 : this->vals_->size(); }
 
 protected:
-  int
+  virtual int
   do_traverse(Traverse* traverse);
 
   bool
@@ -12495,11 +12495,33 @@
     : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
                                    type, indexes, vals, location),
       valtype_(NULL)
-  { go_assert(type->is_slice_type()); }
+  {
+    go_assert(type->is_slice_type());
+
+    mpz_t lenval;
+    Expression* length;
+    if (vals == NULL || vals->empty())
+      mpz_init_set_ui(lenval, 0);
+    else
+      {
+       if (this->indexes() == NULL)
+         mpz_init_set_ui(lenval, vals->size());
+       else
+         mpz_init_set_ui(lenval, indexes->back() + 1);
+      }
+    Type* int_type = Type::lookup_integer_type("int");
+    length = Expression::make_integer(&lenval, int_type, location);
+    mpz_clear(lenval);
+    Type* element_type = type->array_type()->element_type();
+    this->valtype_ = Type::make_array_type(element_type, length);
+  }
 
  protected:
   // Note that taking the address of a slice literal is invalid.
 
+  int
+  do_traverse(Traverse* traverse);
+
   Expression*
   do_copy()
   {
@@ -12518,6 +12540,19 @@
   Type* valtype_;
 };
 
+// Traversal.
+
+int
+Slice_construction_expression::do_traverse(Traverse* traverse)
+{
+  if (this->Array_construction_expression::do_traverse(traverse)
+      == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Type::traverse(this->valtype_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
 // Return the backend representation for constructing a slice.
 
 Bexpression*
@@ -12532,24 +12567,7 @@
 
   Location loc = this->location();
   Type* element_type = array_type->element_type();
-  if (this->valtype_ == NULL)
-    {
-      mpz_t lenval;
-      Expression* length;
-      if (this->vals() == NULL || this->vals()->empty())
-        mpz_init_set_ui(lenval, 0);
-      else
-        {
-          if (this->indexes() == NULL)
-            mpz_init_set_ui(lenval, this->vals()->size());
-          else
-            mpz_init_set_ui(lenval, this->indexes()->back() + 1);
-        }
-      Type* int_type = Type::lookup_integer_type("int");
-      length = Expression::make_integer(&lenval, int_type, loc);
-      mpz_clear(lenval);
-      this->valtype_ = Type::make_array_type(element_type, length);
-    }
+  go_assert(this->valtype_ != NULL);
 
   Expression_list* vals = this->vals();
   if (this->vals() == NULL || this->vals()->empty())
@@ -14028,7 +14046,7 @@
  protected:
   Type*
   do_type()
-  { return Type::make_pointer_type(Type::make_void_type()); }
+  { return Type::lookup_integer_type("uintptr"); }
 
   bool
   do_is_immutable() const
diff -r f6e937cbbe5a go/go.cc
--- a/go/go.cc  Mon Oct 20 11:04:12 2014 -0700
+++ b/go/go.cc  Mon Oct 20 12:04:16 2014 -0700
@@ -96,9 +96,6 @@
   // Create function descriptors as needed.
   ::gogo->create_function_descriptors();
 
-  // Write out queued up functions for hash and comparison of types.
-  ::gogo->write_specific_type_functions();
-
   // Now that we have seen all the names, verify that types are
   // correct.
   ::gogo->verify_types();
@@ -130,6 +127,9 @@
   // Convert complicated go and defer statements into simpler ones.
   ::gogo->simplify_thunk_statements();
 
+  // Write out queued up functions for hash and comparison of types.
+  ::gogo->write_specific_type_functions();
+
   // Flatten the parse tree.
   ::gogo->flatten();
 
diff -r f6e937cbbe5a go/gogo.cc
--- a/go/gogo.cc        Mon Oct 20 11:04:12 2014 -0700
+++ b/go/gogo.cc        Mon Oct 20 12:04:16 2014 -0700
@@ -4196,21 +4196,18 @@
 Expression*
 Gogo::allocate_memory(Type* type, Location location)
 {
-  Btype* btype = type->get_backend(this);
-  size_t size = this->backend()->type_size(btype);
-  mpz_t size_val;
-  mpz_init_set_ui(size_val, size);
-  Type* uintptr = Type::lookup_integer_type("uintptr");
-  Expression* size_expr =
-    Expression::make_integer(&size_val, uintptr, location);
-
-  // If the package imports unsafe, then it may play games with
-  // pointers that look like integers.
+  Expression* td = Expression::make_type_descriptor(type, location);
+  Expression* size =
+    Expression::make_type_info(type, Expression::TYPE_INFO_SIZE);
+
+  // If this package imports unsafe, then it may play games with
+  // pointers that look like integers.  We should be able to determine
+  // whether or not to use new pointers in libgo/go-new.c.  FIXME.
   bool use_new_pointers = this->imported_unsafe_ || type->has_pointer();
   return Runtime::make_call((use_new_pointers
                             ? Runtime::NEW
                             : Runtime::NEW_NOPOINTERS),
-                            location, 1, size_expr);
+                           location, 2, td, size);
 }
 
 // Traversal class used to check for return statements.
diff -r f6e937cbbe5a go/runtime.cc
--- a/go/runtime.cc     Mon Oct 20 11:04:12 2014 -0700
+++ b/go/runtime.cc     Mon Oct 20 12:04:16 2014 -0700
@@ -82,6 +82,7 @@
 runtime_function_type(Runtime_function_type bft)
 {
   go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
+  Type* any = Type::make_pointer_type(Type::make_void_type());
   if (runtime_function_types[bft] == NULL)
     {
       const Location bloc = Linemap::predeclared_location();
@@ -145,13 +146,11 @@
          break;
 
        case RFT_SLICE:
-         t = Type::make_array_type(Type::make_void_type(), NULL);
+         t = Type::make_array_type(any, NULL);
          break;
 
        case RFT_MAP:
-         t = Type::make_map_type(Type::make_void_type(),
-                                 Type::make_void_type(),
-                                 bloc);
+         t = Type::make_map_type(any, any, bloc);
          break;
 
        case RFT_MAPITER:
@@ -159,7 +158,7 @@
          break;
 
        case RFT_CHAN:
-         t = Type::make_channel_type(true, true, Type::make_void_type());
+         t = Type::make_channel_type(true, true, any);
          break;
 
        case RFT_IFACE:
diff -r f6e937cbbe5a go/runtime.def
--- a/go/runtime.def    Mon Oct 20 11:04:12 2014 -0700
+++ b/go/runtime.def    Mon Oct 20 12:04:16 2014 -0700
@@ -221,10 +221,10 @@
 
 
 // Allocate memory.
-DEF_GO_RUNTIME(NEW, "__go_new", P1(UINTPTR), R1(POINTER))
+DEF_GO_RUNTIME(NEW, "__go_new", P2(TYPE, UINTPTR), R1(POINTER))
 
 // Allocate memory which can not contain pointers.
-DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
+DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P2(TYPE, UINTPTR), 
R1(POINTER))
 
 
 // Start a new goroutine.
diff -r f6e937cbbe5a go/statements.cc
--- a/go/statements.cc  Mon Oct 20 11:04:12 2014 -0700
+++ b/go/statements.cc  Mon Oct 20 12:04:16 2014 -0700
@@ -1878,7 +1878,7 @@
 
   mpz_t oval;
   mpz_init_set_ui(oval, 1UL);
-  Expression* oexpr = Expression::make_integer(&oval, NULL, loc);
+  Expression* oexpr = Expression::make_integer(&oval, this->expr_->type(), 
loc);
   mpz_clear(oval);
 
   Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
diff -r f6e937cbbe5a go/types.cc
--- a/go/types.cc       Mon Oct 20 11:04:12 2014 -0700
+++ b/go/types.cc       Mon Oct 20 12:04:16 2014 -0700
@@ -1244,6 +1244,25 @@
       phash = &ins.first->second;
     }
 
+  // The type descriptor symbol for the unsafe.Pointer type is defined in
+  // libgo/go-unsafe-pointer.c, so we just return a reference to that
+  // symbol if necessary.
+  if (this->is_unsafe_pointer_type())
+    {
+      Location bloc = Linemap::predeclared_location();
+
+      Type* td_type = Type::make_type_descriptor_type();
+      Btype* td_btype = td_type->get_backend(gogo);
+      this->type_descriptor_var_ =
+       gogo->backend()->immutable_struct_reference("__go_tdn_unsafe.Pointer",
+                                                   td_btype,
+                                                   bloc);
+
+      if (phash != NULL)
+       *phash = this->type_descriptor_var_;
+      return;
+    }
+
   std::string var_name = this->type_descriptor_var_name(gogo, nt);
 
   // Build the contents of the type descriptor.
@@ -1540,7 +1559,7 @@
                                       "hash", uint32_type,
                                       "hashfn", uintptr_type,
                                       "equalfn", uintptr_type,
-                                      "gc", unsafe_pointer_type,
+                                      "gc", uintptr_type,
                                       "string", pointer_string_type,
                                       "", pointer_uncommon_type,
                                       "ptrToThis",
@@ -6027,7 +6046,6 @@
   tref->set_is_lvalue();
   s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, tref, ele_size,
                                           bloc);
-
   Block* statements = gogo->finish_block(bloc);
 
   for_range->add_statements(statements);
diff -r f6e937cbbe5a libgo/runtime/go-new.c
--- a/libgo/runtime/go-new.c    Mon Oct 20 11:04:12 2014 -0700
+++ b/libgo/runtime/go-new.c    Mon Oct 20 12:04:16 2014 -0700
@@ -10,13 +10,17 @@
 #include "malloc.h"
 
 void *
-__go_new (uintptr_t size)
+__go_new (const struct __go_type_descriptor *td, uintptr_t size)
 {
-  return runtime_mallocgc (size, 0, 0);
+  return runtime_mallocgc (size,
+                          (uintptr) td | TypeInfo_SingleObject,
+                          0);
 }
 
 void *
-__go_new_nopointers (uintptr_t size)
+__go_new_nopointers (const struct __go_type_descriptor *td,  uintptr_t size)
 {
-  return runtime_mallocgc (size, 0, FlagNoScan);
+  return runtime_mallocgc (size,
+                          (uintptr) td | TypeInfo_SingleObject,
+                          FlagNoScan);
 }

Reply via email to