compiler: Add precise type information on the heap.
authorChris Manghane <cmang@google.com>
Wed, 3 Sep 2014 22:56:09 +0000 (22:56 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 3 Sep 2014 22:56:09 +0000 (22:56 +0000)
* go-gcc.cc (Gcc_backend::implicit_variable): Remove init
parameter.  Add is_hidden parameter.
(Gcc_backend::implicit_variable_set_init): New method.
(Gcc_backend::implicit_variable_reference): New method.

From-SVN: r214894

14 files changed:
gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h
libgo/go/reflect/type.go
libgo/go/runtime/type.go
libgo/runtime/go-type.h
libgo/runtime/go-unsafe-pointer.c
libgo/runtime/mgc0.c
libgo/runtime/runtime.h

index f7c44c5f11266b446d318512e4ee3ca0725ce116..9a759ac0af852a5333af280a3808881afe1f9f07 100644 (file)
@@ -1,3 +1,10 @@
+2014-09-03  Chris Manghane  <cmang@google.com>
+
+       * go-gcc.cc (Gcc_backend::implicit_variable): Remove init
+       parameter.  Add is_hidden parameter.
+       (Gcc_backend::implicit_variable_set_init): New method.
+       (Gcc_backend::implicit_variable_reference): New method.
+
 2014-08-08  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (Gcc_backend::compound_statement): Don't return
index 059706e039fd9df1cd84340e2629c0254252da61..6bac84f2565f3c0a9a98280573968f926966b02c 100644 (file)
@@ -389,9 +389,16 @@ class Gcc_backend : public Backend
                     Location, Bstatement**);
 
   Bvariable*
-  implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
+  implicit_variable(const std::string&, Btype*, bool, bool, bool,
                    size_t);
 
+  void
+  implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
+                            bool, bool, bool, Bexpression*);
+
+  Bvariable*
+  implicit_variable_reference(const std::string&, Btype*);
+
   Bvariable*
   immutable_struct(const std::string&, bool, bool, Btype*, Location);
 
@@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
 
 Bvariable*
 Gcc_backend::implicit_variable(const std::string& name, Btype* type,
-                              Bexpression* init, bool is_constant,
+                              bool is_hidden, bool is_constant,
                               bool is_common, size_t alignment)
 {
   tree type_tree = type->get_tree();
-  tree init_tree;
-  if (init == NULL)
-    init_tree = NULL_TREE;
-  else
-    init_tree = init->get_tree();
-  if (type_tree == error_mark_node || init_tree == error_mark_node)
+  if (type_tree == error_mark_node)
     return this->error_variable();
 
   tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
                          get_identifier_from_string(name), type_tree);
   DECL_EXTERNAL(decl) = 0;
-  TREE_PUBLIC(decl) = 0;
+  TREE_PUBLIC(decl) = !is_hidden;
   TREE_STATIC(decl) = 1;
+  TREE_USED(decl) = 1;
   DECL_ARTIFICIAL(decl) = 1;
   if (is_common)
     {
       DECL_COMMON(decl) = 1;
-      TREE_PUBLIC(decl) = 1;
-      gcc_assert(init_tree == NULL_TREE);
+
+      // When the initializer for one implicit_variable refers to another,
+      // it needs to know the visibility of the referenced struct so that
+      // compute_reloc_for_constant will return the right value.  On many
+      // systems calling make_decl_one_only will mark the decl as weak,
+      // which will change the return value of compute_reloc_for_constant.
+      // We can't reliably call make_decl_one_only yet, because we don't
+      // yet know the initializer.  This issue doesn't arise in C because
+      // Go initializers, unlike C initializers, can be indirectly
+      // recursive.  To ensure that compute_reloc_for_constant computes
+      // the right value if some other initializer refers to this one, we
+      // mark this symbol as weak here.  We undo that below in
+      // immutable_struct_set_init before calling mark_decl_one_only.
+      DECL_WEAK(decl) = 1;
     }
-  else if (is_constant)
+  if (is_constant)
     {
       TREE_READONLY(decl) = 1;
       TREE_CONSTANT(decl) = 1;
     }
-  DECL_INITIAL(decl) = init_tree;
-
   if (alignment != 0)
     {
       DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
       DECL_USER_ALIGN(decl) = 1;
     }
 
+  go_preserve_from_gc(decl);
+  return new Bvariable(decl);
+}
+
+// Set the initalizer for a variable created by implicit_variable.
+// This is where we finish compiling the variable.
+
+void
+Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
+                                       Btype*, bool, bool, bool is_common,
+                                       Bexpression* init)
+{
+  tree decl = var->get_tree();
+  tree init_tree;
+  if (init == NULL)
+    init_tree = NULL_TREE;
+  else
+    init_tree = init->get_tree();
+  if (decl == error_mark_node || init_tree == error_mark_node)
+    return;
+
+  DECL_INITIAL(decl) = init_tree;
+
+  // Now that DECL_INITIAL is set, we can't call make_decl_one_only.
+  // See the comment where DECL_WEAK is set in implicit_variable.
+  if (is_common)
+    {
+      DECL_WEAK(decl) = 0;
+      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+    }
+
+  resolve_unique_section(decl, 2, 1);
+
   rest_of_decl_compilation(decl, 1, 0);
+}
 
+// Return a reference to an implicit variable defined in another package.
+
+Bvariable*
+Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+
+  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+                         get_identifier_from_string(name), type_tree);
+  DECL_EXTERNAL(decl) = 0;
+  TREE_PUBLIC(decl) = 1;
+  TREE_STATIC(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+  go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
 
index 323ac2e75b510c4f6a3d15b5e4528f34b8513f95..98c36c1f5f881259004ee6e0fcf06e110b530f4b 100644 (file)
@@ -545,24 +545,55 @@ class Backend
                     Bstatement** pstatement) = 0;
 
   // Create an implicit variable that is compiler-defined.  This is
-  // used when generating GC root variables, when storing the values
-  // of a slice constructor, and for the zero value of types.  NAME is
-  // the name of the variable, either gc# for GC roots or C# for slice
-  // initializers.  TYPE is the type of the implicit variable with an
-  // initial value INIT.  IS_CONSTANT is true if the implicit variable
-  // should be treated like it is immutable.  For slice initializers,
-  // if the values must be copied to the heap, the variable
-  // IS_CONSTANT.  IS_COMMON is true if the implicit variable should
+  // used when generating GC data and roots, when storing the values
+  // of a slice constructor, and for the zero value of types.  This returns a
+  // Bvariable because it corresponds to an initialized variable in C.
+  //
+  // NAME is the name to use for the initialized variable this will create.
+  //
+  // TYPE is the type of the implicit variable. 
+  //
+  // IS_HIDDEN will be true if the descriptor should only be visible
+  // within the current object.
+  //
+  // IS_CONSTANT is true if the implicit variable should be treated like it is
+  // immutable.  For slice initializers, if the values must be copied to the
+  // heap, the variable IS_CONSTANT.
+  //
+  // IS_COMMON is true if the implicit variable should
   // be treated as a common variable (multiple definitions with
   // different sizes permitted in different object files, all merged
   // into the largest definition at link time); this will be true for
-  // the zero value.  If IS_COMMON is true, INIT will be NULL, and the
-  // variable should be initialized to all zeros.  If ALIGNMENT is not
-  // zero, it is the desired alignment of the variable.
+  // the zero value.  IS_HIDDEN and IS_COMMON will never both be true.
+  //
+  // If ALIGNMENT is not zero, it is the desired alignment of the variable.
   virtual Bvariable*
-  implicit_variable(const std::string& name, Btype* type, Bexpression* init,
+  implicit_variable(const std::string& name, Btype* type, bool is_hidden,
                    bool is_constant, bool is_common, size_t alignment) = 0;
 
+
+  // Set the initial value of a variable created by implicit_variable.
+  // This must be called even if there is no initializer, i.e., INIT is NULL.
+  // The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are
+  // the same ones passed to implicit_variable.  INIT will be a composite
+  // literal of type TYPE.  It will not contain any function calls or anything
+  // else that can not be put into a read-only data section.
+  // It may contain the address of variables created by implicit_variable.
+  //
+  // If IS_COMMON is true, INIT will be NULL, and the
+  // variable should be initialized to all zeros.
+  virtual void
+  implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type,
+                            bool is_hidden, bool is_constant, bool is_common,
+                            Bexpression* init) = 0;
+
+  // Create a reference to a named implicit variable defined in some other
+  // package.  This will be a variable created by a call to implicit_variable
+  // with the same NAME and TYPE and with IS_COMMON passed as false.  This
+  // corresponds to an extern global variable in C.
+  virtual Bvariable*
+  implicit_variable_reference(const std::string& name, Btype* type) = 0;
+
   // Create a named immutable initialized data structure.  This is
   // used for type descriptors, map descriptors, and function
   // descriptors.  This returns a Bvariable because it corresponds to
index 6414136fed01b7d2484e1af614c339e8e534b695..df1650a172a6af6f877fd922018862f34de121b8 100644 (file)
@@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression
   int
   do_traverse(Traverse* traverse);
 
+  bool
+  do_is_immutable() const;
+
   Type*
   do_type()
   { return this->type_; }
@@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
   return TRAVERSE_CONTINUE;
 }
 
+// Return whether an unsafe type conversion is immutable.
+
+bool
+Unsafe_type_conversion_expression::do_is_immutable() const
+{
+  Type* type = this->type_;
+  Type* expr_type = this->expr_->type();
+
+  if (type->interface_type() != NULL
+      || expr_type->interface_type() != NULL)
+    return false;
+
+  if (!this->expr_->is_immutable())
+    return false;
+
+  if (Type::are_convertible(type, expr_type, NULL))
+    return true;
+
+  return type->is_basic_type() && expr_type->is_basic_type();
+}
+
 // Convert to backend representation.
 
 Bexpression*
@@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context)
                              && !context->is_const());
            }
          Bvariable* implicit =
-           gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap,
+           gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
                                               false, 0);
+         gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
+                                                     true, copy_to_heap, false,
+                                                     bexpr);
          bexpr = gogo->backend()->var_expression(implicit, loc);
        }
       else if ((this->expr_->is_composite_literal()
@@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location)
   return new Type_descriptor_expression(type, location);
 }
 
+// An expression which evaluates to a pointer to the Garbage Collection symbol
+// of a type.
+
+class GC_symbol_expression : public Expression
+{
+ public:
+  GC_symbol_expression(Type* type)
+    : Expression(EXPRESSION_GC_SYMBOL, Linemap::predeclared_location()),
+      type_(type)
+  {}
+
+ protected:
+  Type*
+  do_type()
+  { return Type::make_pointer_type(Type::make_void_type()); }
+
+  bool
+  do_is_immutable() const
+  { return true; }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  Bexpression*
+  do_get_backend(Translate_context* context)
+  { return this->type_->gc_symbol_pointer(context->gogo()); }
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The type which this gc symbol describes.
+  Type* type_;
+};
+
+// Dump ast representation for a gc symbol expression.
+
+void
+GC_symbol_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "gcdata(";
+  ast_dump_context->dump_type(this->type_);
+  ast_dump_context->ostream() << ")";
+}
+
+// Make a gc symbol expression.
+
+Expression*
+Expression::make_gc_symbol(Type* type)
+{
+  return new GC_symbol_expression(type);
+}
+
 // An expression which evaluates to some characteristic of a type.
 // This is only used to initialize fields of a type descriptor.  Using
 // a new expression class is slightly inefficient but gives us a good
index 0ce6f22706a8bbd664113dbd86b44a34ff62e4bb..77153dbd58f678fa4988bbb62247f0ddceab73db 100644 (file)
@@ -103,6 +103,7 @@ class Expression
     EXPRESSION_HEAP,
     EXPRESSION_RECEIVE,
     EXPRESSION_TYPE_DESCRIPTOR,
+    EXPRESSION_GC_SYMBOL,
     EXPRESSION_TYPE_INFO,
     EXPRESSION_SLICE_INFO,
     EXPRESSION_SLICE_VALUE,
@@ -349,6 +350,11 @@ class Expression
   static Expression*
   make_type_descriptor(Type* type, Location);
 
+  // Make an expression which evaluates to the address of the gc
+  // symbol for TYPE.
+  static Expression*
+  make_gc_symbol(Type* type);
+
   // Make an expression which evaluates to some characteristic of a
   // type.  These are only used for type descriptors, so there is no
   // location parameter.
@@ -1512,6 +1518,10 @@ class Binary_expression : public Expression
   do_is_constant() const
   { return this->left_->is_constant() && this->right_->is_constant(); }
 
+  bool
+  do_is_immutable() const
+  { return this->left_->is_immutable() && this->right_->is_immutable(); }
+
   bool
   do_numeric_constant_value(Numeric_constant*) const;
 
index 654b6c3df93e31e7f6b7d7ad6db36526dc4d41c3..dcc2ae64961a0e581b76ae7c4f018e5f5a1033c3 100644 (file)
@@ -655,9 +655,13 @@ Gogo::backend_zero_value()
 
   Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
 
-  return this->backend()->implicit_variable(this->zero_value_->name(),
-                                           barray_type, NULL, true, true,
-                                           this->zero_value_align_);
+  std::string zname = this->zero_value_->name();
+  Bvariable* zvar =
+    this->backend()->implicit_variable(zname, barray_type, false,
+                                      true, true, this->zero_value_align_);
+  this->backend()->implicit_variable_set_init(zvar, zname, barray_type,
+                                             false, true, true, NULL);
+  return zvar;
 }
 
 // Add statements to INIT_STMTS which run the initialization
@@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
           {
             named_type->
                 type_descriptor_pointer(gogo, Linemap::predeclared_location());
+           named_type->gc_symbol_pointer(gogo);
             Type* pn = Type::make_pointer_type(named_type);
             pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
+           pn->gc_symbol_pointer(gogo);
           }
       }
       break;
index 395b5e55081d8d911e2fb5d116137fc6532c0230..302faeee3538aa04bfcff62fcbe0589b0d772912 100644 (file)
@@ -36,7 +36,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
 // Class Type.
 
 Type::Type(Type_classification classification)
-  : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
+  : classification_(classification), btype_(NULL), type_descriptor_var_(NULL),
+    gc_symbol_var_(NULL)
 {
 }
 
@@ -1236,7 +1237,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
        Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
       if (!ins.second)
        {
-         // We've already build a type descriptor for this type.
+         // We've already built a type descriptor for this type.
          this->type_descriptor_var_ = ins.first->second;
          return;
        }
@@ -1405,6 +1406,18 @@ Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
   return type->do_type_descriptor(gogo, name);
 }
 
+// Generate the GC symbol for this TYPE.  VALS is the data so far in this
+// symbol; extra values will be appended in do_gc_symbol.  OFFSET is the
+// offset into the symbol where the GC data is located.  STACK_SIZE is the
+// size of the GC stack when dealing with array types.
+
+void
+Type::gc_symbol(Gogo* gogo, Type* type, Expression_list** vals,
+               Expression** offset, int stack_size)
+{
+  type->do_gc_symbol(gogo, vals, offset, stack_size);
+}
+
 // Make a builtin struct type from a list of fields.  The fields are
 // pairs of a name and a type.
 
@@ -1519,14 +1532,15 @@ Type::make_type_descriptor_type()
       // The type descriptor type.
 
       Struct_type* type_descriptor_type =
-       Type::make_builtin_struct_type(11,
-                                      "Kind", uint8_type,
+       Type::make_builtin_struct_type(12,
+                                      "kind", uint8_type,
                                       "align", uint8_type,
                                       "fieldAlign", uint8_type,
                                       "size", uintptr_type,
                                       "hash", uint32_type,
                                       "hashfn", uintptr_type,
                                       "equalfn", uintptr_type,
+                                      "gc", unsafe_pointer_type,
                                       "string", pointer_string_type,
                                       "", pointer_uncommon_type,
                                       "ptrToThis",
@@ -1973,7 +1987,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
   if (!this->has_pointer())
     runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
   Struct_field_list::const_iterator p = fields->begin();
-  go_assert(p->is_field_name("Kind"));
+  go_assert(p->is_field_name("kind"));
   mpz_t iv;
   mpz_init_set_ui(iv, runtime_type_kind);
   vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
@@ -2018,6 +2032,10 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
   vals->push_back(Expression::make_func_code_reference(hash_fn, bloc));
   vals->push_back(Expression::make_func_code_reference(equal_fn, bloc));
 
+  ++p;
+  go_assert(p->is_field_name("gc"));
+  vals->push_back(Expression::make_gc_symbol(this));
+
   ++p;
   go_assert(p->is_field_name("string"));
   Expression* s = Expression::make_string((name != NULL
@@ -2067,6 +2085,160 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
   return Expression::make_struct_composite_literal(td_type, vals, bloc);
 }
 
+// Return a pointer to the Garbage Collection information for this type.
+
+Bexpression*
+Type::gc_symbol_pointer(Gogo* gogo)
+{
+  Type* t = this->forwarded();
+  if (t->named_type() != NULL && t->named_type()->is_alias())
+    t = t->named_type()->real_type();
+  if (t->gc_symbol_var_ == NULL)
+    {
+      t->make_gc_symbol_var(gogo);
+      go_assert(t->gc_symbol_var_ != NULL);
+    }
+  Location bloc = Linemap::predeclared_location();
+  Bexpression* var_expr =
+      gogo->backend()->var_expression(t->gc_symbol_var_, bloc);
+  return gogo->backend()->address_expression(var_expr, bloc);
+}
+
+// A mapping from unnamed types to GC symbol variables.
+
+Type::GC_symbol_vars Type::gc_symbol_vars;
+
+// Build the GC symbol for this type.
+
+void
+Type::make_gc_symbol_var(Gogo* gogo)
+{
+  go_assert(this->gc_symbol_var_ == NULL);
+
+  Named_type* nt = this->named_type();
+
+  // We can have multiple instances of unnamed types and similar to type
+  // descriptors, we only want to the emit the GC data once, so we use a
+  // hash table.
+  Bvariable** phash = NULL;
+  if (nt == NULL)
+    {
+      Bvariable* bvnull = NULL;
+      std::pair<GC_symbol_vars::iterator, bool> ins =
+       Type::gc_symbol_vars.insert(std::make_pair(this, bvnull));
+      if (!ins.second)
+       {
+         // We've already built a gc symbol for this type.
+         this->gc_symbol_var_ = ins.first->second;
+         return;
+       }
+      phash = &ins.first->second;
+    }
+
+  std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
+
+  // Build the contents of the gc symbol.
+  Expression* sym_init = this->gc_symbol_constructor(gogo);
+  Btype* sym_btype = sym_init->type()->get_backend(gogo);
+
+  // If the type descriptor for this type is defined somewhere else, so is the
+  // GC symbol.
+  const Package* dummy;
+  if (this->type_descriptor_defined_elsewhere(nt, &dummy))
+    {
+      this->gc_symbol_var_ =
+       gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
+      if (phash != NULL)
+       *phash = this->gc_symbol_var_;
+      return;
+    }
+
+  // See if this gc symbol can appear in multiple packages.
+  bool is_common = false;
+  if (nt != NULL)
+    {
+      // We create the symbol for a builtin type whenever we need
+      // it.
+      is_common = nt->is_builtin();
+    }
+  else
+    {
+      // This is an unnamed type.  The descriptor could be defined in
+      // any package where it is needed, and the linker will pick one
+      // descriptor to keep.
+      is_common = true;
+    }
+
+  // Since we are building the GC symbol in this package, we must create the
+  // variable before converting the initializer to its backend representation
+  // because the initializer may refer to the GC symbol for this type.
+  this->gc_symbol_var_ =
+    gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
+  if (phash != NULL)
+    *phash = this->gc_symbol_var_;
+
+  Translate_context context(gogo, NULL, NULL, NULL);
+  context.set_is_const();
+  Bexpression* sym_binit = sym_init->get_backend(&context);
+  gogo->backend()->implicit_variable_set_init(this->gc_symbol_var_, sym_name,
+                                             sym_btype, false, true, is_common,
+                                             sym_binit);
+}
+
+// Return an array literal for the Garbage Collection information for this type.
+
+Expression*
+Type::gc_symbol_constructor(Gogo* gogo)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  // The common GC Symbol data starts with the width of the type and ends
+  // with the GC Opcode GC_END.
+  // However, for certain types, the GC symbol may include extra information
+  // before the ending opcode, so we pass the expression list into
+  // Type::gc_symbol to allow it to add extra information as is necessary.
+  Expression_list* vals = new Expression_list;
+
+  Type* uintptr_t = Type::lookup_integer_type("uintptr");
+  // width
+  vals->push_back(Expression::make_type_info(this,
+                                            Expression::TYPE_INFO_SIZE));
+
+  mpz_t off;
+  mpz_init_set_ui(off, 0UL);
+  Expression* offset = Expression::make_integer(&off, uintptr_t, bloc);
+  mpz_clear(off);
+
+  this->do_gc_symbol(gogo, &vals, &offset, 0);
+
+  mpz_t end;
+  mpz_init_set_ui(end, GC_END);
+  vals->push_back(Expression::make_integer(&end, uintptr_t, bloc));
+  mpz_clear(end);
+
+  mpz_t lenval;
+  mpz_init_set_ui(lenval, vals->size() + 1);
+  Expression* len = Expression::make_integer(&lenval, NULL, bloc);
+  mpz_clear(lenval);
+
+  Array_type* gc_symbol_type = Type::make_array_type(uintptr_t, len);
+  return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
+}
+
+// Advance the OFFSET of the GC symbol by this type's width.
+
+void
+Type::advance_gc_offset(Expression** offset)
+{
+  if (this->is_error_type())
+    return;
+
+  Location bloc = Linemap::predeclared_location();
+  Expression* width =
+    Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
+  *offset = Expression::make_binary(OPERATOR_PLUS, *offset, width, bloc);
+}
+
 // Return a composite literal for the uncommon type information for
 // this type.  UNCOMMON_STRUCT_TYPE is the type of the uncommon type
 // struct.  If name is not NULL, it is the name of the type.  If
@@ -2497,6 +2669,10 @@ class Error_type : public Type
   do_reflection(Gogo*, std::string*) const
   { go_assert(saw_errors()); }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+  { go_assert(saw_errors()); }
+
   void
   do_mangled_name(Gogo*, std::string* ret) const
   { ret->push_back('E'); }
@@ -2535,6 +2711,10 @@ class Void_type : public Type
   do_reflection(Gogo*, std::string*) const
   { }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+  { }
+
   void
   do_mangled_name(Gogo*, std::string* ret) const
   { ret->push_back('v'); }
@@ -2573,6 +2753,9 @@ class Boolean_type : public Type
   do_reflection(Gogo*, std::string* ret) const
   { ret->append("bool"); }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string* ret) const
   { ret->push_back('b'); }
@@ -2593,6 +2776,12 @@ Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
     }
 }
 
+// Update the offset of the GC symbol.
+
+void
+Boolean_type::do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+{ this->advance_gc_offset(offset); }
+
 Type*
 Type::make_boolean_type()
 {
@@ -3102,6 +3291,22 @@ String_type::do_reflection(Gogo*, std::string* ret) const
   ret->append("string");
 }
 
+// Generate GC symbol for strings.
+
+void
+String_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                         Expression** offset, int)
+{
+  Location bloc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+  mpz_t opval;
+  mpz_init_set_ui(opval, GC_STRING);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name of a string type.
 
 void
@@ -3172,6 +3377,10 @@ class Sink_type : public Type
   do_reflection(Gogo*, std::string*) const
   { go_unreachable(); }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+  { go_unreachable(); }
+
   void
   do_mangled_name(Gogo*, std::string*) const
   { go_unreachable(); }
@@ -3754,6 +3963,25 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
     }
 }
 
+// Generate GC symbol for a function type.
+
+void
+Function_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                           Expression** offset, int)
+{
+  Location bloc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  // We use GC_APTR here because we do not currently have a way to describe the
+  // the type of the possible function closure.  FIXME.
+  mpz_t opval;
+  mpz_init_set_ui(opval, GC_APTR);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name.
 
 void
@@ -4156,6 +4384,26 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
   this->append_reflection(this->to_type_, gogo, ret);
 }
 
+// Generate GC symbol for pointer types.
+
+void
+Pointer_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                          Expression** offset, int)
+{
+  Location loc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  mpz_t opval;
+  mpz_init_set_ui(opval, this->to_type_->has_pointer() ? GC_PTR : GC_APTR);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, loc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+
+  if (this->to_type_->has_pointer())
+    (*vals)->push_back(Expression::make_gc_symbol(this->to_type_));
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name.
 
 void
@@ -4235,6 +4483,10 @@ class Nil_type : public Type
   do_reflection(Gogo*, std::string*) const
   { go_unreachable(); }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+  { go_unreachable(); }
+
   void
   do_mangled_name(Gogo*, std::string* ret) const
   { ret->push_back('n'); }
@@ -4292,6 +4544,10 @@ class Call_multiple_result_type : public Type
   do_reflection(Gogo*, std::string*) const
   { go_assert(saw_errors()); }
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+  { go_unreachable(); }
+
   void
   do_mangled_name(Gogo*, std::string*) const
   { go_assert(saw_errors()); }
@@ -5319,6 +5575,27 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
   ret->push_back('}');
 }
 
+// Generate GC symbol for struct types.
+
+void
+Struct_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+                         Expression** offset, int stack_size)
+{
+  Location bloc = Linemap::predeclared_location();
+  const Struct_field_list* sfl = this->fields();
+  for (Struct_field_list::const_iterator p = sfl->begin();
+       p != sfl->end();
+       ++p)
+    {
+      Expression* field_offset =
+       Expression::make_struct_field_offset(this, &*p);
+      Expression* o =
+       Expression::make_binary(OPERATOR_PLUS, *offset, field_offset, bloc);
+      Type::gc_symbol(gogo, p->type(), vals, &o, stack_size);
+    }
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name.
 
 void
@@ -6204,6 +6481,115 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
   this->append_reflection(this->element_type_, gogo, ret);
 }
 
+// GC Symbol construction for array types.
+
+void
+Array_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+                        Expression** offset, int stack_size)
+{
+  if (this->length_ == NULL)
+    this->slice_gc_symbol(gogo, vals, offset, stack_size);
+  else
+    this->array_gc_symbol(gogo, vals, offset, stack_size);
+}
+
+// Generate the GC Symbol for a slice.
+
+void
+Array_type::slice_gc_symbol(Gogo* gogo, Expression_list** vals,
+                           Expression** offset, int)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  // Differentiate between slices with zero-length and non-zero-length values.
+  Type* element_type = this->element_type();
+  Btype* ebtype = element_type->get_backend(gogo);
+  size_t element_size = gogo->backend()->type_size(ebtype);
+
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+  mpz_t opval;
+  mpz_init_set_ui(opval, element_size == 0 ? GC_APTR : GC_SLICE);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+
+  if (element_size != 0)
+    (*vals)->push_back(Expression::make_gc_symbol(element_type));
+  this->advance_gc_offset(offset);
+}
+
+// Generate the GC symbol for an array.
+
+void
+Array_type::array_gc_symbol(Gogo* gogo, Expression_list** vals,
+                           Expression** offset, int stack_size)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  Numeric_constant nc;
+  unsigned long bound;
+  if (!this->length_->numeric_constant_value(&nc)
+      || nc.to_unsigned_long(&bound) == Numeric_constant::NC_UL_NOTINT)
+    go_assert(saw_errors());
+
+  Btype* pbtype = gogo->backend()->pointer_type(gogo->backend()->void_type());
+  size_t pwidth = gogo->backend()->type_size(pbtype);
+  size_t iwidth = gogo->backend()->type_size(this->get_backend(gogo));
+
+  Type* element_type = this->element_type();
+  if (bound < 1 || !element_type->has_pointer())
+    this->advance_gc_offset(offset);
+  else if (bound == 1 || iwidth <= 4 * pwidth)
+    {
+      for (unsigned int i = 0; i < bound; ++i)
+       Type::gc_symbol(gogo, element_type, vals, offset, stack_size);
+    }
+  else
+    {
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+      mpz_t op;
+      if (stack_size < GC_STACK_CAPACITY)
+       {
+         mpz_init_set_ui(op, GC_ARRAY_START);
+         (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+         mpz_clear(op);
+         (*vals)->push_back(*offset);
+         Expression* uintptr_len =
+           Expression::make_cast(uintptr_type, this->length_, bloc);
+         (*vals)->push_back(uintptr_len);
+
+         Expression* width =
+           Expression::make_type_info(element_type,
+                                      Expression::TYPE_INFO_SIZE);
+         (*vals)->push_back(width);
+
+         mpz_t zero;
+         mpz_init_set_ui(zero, 0UL);
+         Expression* offset2 =
+           Expression::make_integer(&zero, uintptr_type, bloc);
+         mpz_clear(zero);
+
+         Type::gc_symbol(gogo, element_type, vals, &offset2, stack_size + 1);
+         mpz_init_set_ui(op, GC_ARRAY_NEXT);
+         (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+       }
+      else
+       {
+         mpz_init_set_ui(op, GC_REGION);
+         (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+         (*vals)->push_back(*offset);
+
+         Expression* width =
+           Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
+         (*vals)->push_back(width);
+         (*vals)->push_back(Expression::make_gc_symbol(this));
+       }
+      mpz_clear(op);
+      this->advance_gc_offset(offset);
+    }
+}
+
 // Mangled name.
 
 void
@@ -6513,6 +6899,24 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
   this->append_reflection(this->val_type_, gogo, ret);
 }
 
+// Generate GC symbol for a map.
+
+void
+Map_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                      Expression** offset, int)
+{
+  // TODO(cmang): Generate GC data for the Map elements.
+  Location bloc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  mpz_t opval;
+  mpz_init_set_ui(opval, GC_APTR);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name for a map.
 
 void
@@ -6686,6 +7090,30 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
   this->append_reflection(this->element_type_, gogo, ret);
 }
 
+// Generate GC symbol for channels.
+
+void
+Channel_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                          Expression** offset, int)
+{
+  Location bloc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  mpz_t opval;
+  mpz_init_set_ui(opval, GC_CHAN_PTR);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+  Type* unsafeptr_type = Type::make_pointer_type(Type::make_void_type());
+  Expression* type_descriptor =
+    Expression::make_type_descriptor(this, bloc);
+  type_descriptor =
+    Expression::make_unsafe_cast(unsafeptr_type, type_descriptor, bloc);
+  (*vals)->push_back(type_descriptor);
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name.
 
 void
@@ -7574,6 +8002,24 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
   ret->append("}");
 }
 
+// Generate GC symbol for interface types.
+
+void
+Interface_type::do_gc_symbol(Gogo*, Expression_list** vals,
+                            Expression** offset, int)
+{
+  Location bloc = Linemap::predeclared_location();
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  mpz_t opval;
+  mpz_init_set_ui(opval, this->is_empty() ? GC_EFACE : GC_IFACE);
+  (*vals)->push_back(Expression::make_integer(&opval, uintptr_type,
+                                             bloc));
+  mpz_clear(opval);
+  (*vals)->push_back(*offset);
+  this->advance_gc_offset(offset);
+}
+
 // Mangled name.
 
 void
@@ -8810,6 +9256,20 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
   ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
 }
 
+// Generate GC symbol for named types.
+
+void
+Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+                        Expression** offset, int stack)
+{
+  if (!this->seen_)
+    {
+      this->seen_ = true;
+      Type::gc_symbol(gogo, this->real_type(), vals, offset, stack);
+      this->seen_ = false;
+    }
+}
+
 // Get the mangled name.
 
 void
index 6fa65133a0ef609cb5425f6f7bcc0f6d3e5e97ac..447861c4846842259d8f1537d27ca8ba679d1ebc 100644 (file)
@@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
 
 static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
 
+// GC instruction opcodes.  These must match the values in libgo/runtime/mgc0.h.
+enum GC_Opcode
+{
+  GC_END = 0,     // End of object, loop or subroutine.
+  GC_PTR,         // A typed pointer.
+  GC_APTR,        // Pointer to an arbitrary object.
+  GC_ARRAY_START, // Start an array with a fixed length.
+  GC_ARRAY_NEXT,  // The next element of an array.
+  GC_CALL,        // Call a subroutine.
+  GC_CHAN_PTR,    // Go channel.
+  GC_STRING,      // Go string.
+  GC_EFACE,       // interface{}.
+  GC_IFACE,       // interface{...}.
+  GC_SLICE,       // Go slice.
+  GC_REGION,      // A region/part of the current object.
+
+  GC_NUM_INSTR    // Number of instruction opcodes
+};
+
+// The GC Stack Capacity must match the value in libgo/runtime/mgc0.h.
+static const int GC_STACK_CAPACITY = 8;
+
 // To build the complete list of methods for a named type we need to
 // gather all methods from anonymous fields.  Those methods may
 // require an arbitrary set of indirections and field offsets.  There
@@ -911,6 +933,10 @@ class Type
   Bexpression*
   type_descriptor_pointer(Gogo* gogo, Location);
 
+  // Build the Garbage Collection symbol for this type.  Return a pointer to it.
+  Bexpression*
+  gc_symbol_pointer(Gogo* gogo);
+
   // Return the type reflection string for this type.
   std::string
   reflection(Gogo*) const;
@@ -995,6 +1021,9 @@ class Type
   virtual Expression*
   do_type_descriptor(Gogo*, Named_type* name) = 0;
 
+  virtual void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int) = 0;
+
   virtual void
   do_reflection(Gogo*, std::string*) const = 0;
 
@@ -1050,6 +1079,22 @@ class Type
   type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
                              const Methods*, bool only_value_methods);
 
+  // Generate the GC symbol for this TYPE.  VALS is the data so far in this
+  // symbol; extra values will be appended in do_gc_symbol.  OFFSET is the
+  // offset into the symbol where the GC data is located.  STACK_SIZE is the
+  // size of the GC stack when dealing with array types.
+  static void
+  gc_symbol(Gogo*, Type* type, Expression_list** vals, Expression** offset,
+           int stack_size);
+
+  // Build a composite literal for the GC symbol of this type.
+  Expression*
+  gc_symbol_constructor(Gogo*);
+
+  // Advance the OFFSET of the GC symbol by the size of this type.
+  void
+  advance_gc_offset(Expression** offset);
+
   // For the benefit of child class reflection string generation.
   void
   append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
@@ -1126,6 +1171,16 @@ class Type
   void
   make_type_descriptor_var(Gogo*);
 
+  // Map unnamed types to type descriptor decls.
+  typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
+                            Type_identical) GC_symbol_vars;
+
+  static GC_symbol_vars gc_symbol_vars;
+
+  // Build the GC symbol for this type.
+  void
+  make_gc_symbol_var(Gogo*);
+
   // Return the name of the type descriptor variable.  If NAME is not
   // NULL, it is the name to use.
   std::string
@@ -1253,6 +1308,9 @@ class Type
   // The type descriptor for this type.  This starts out as NULL and
   // is filled in as needed.
   Bvariable* type_descriptor_var_;
+  // The GC symbol for this type.  This starts out as NULL and
+  // is filled in as needed.
+  Bvariable* gc_symbol_var_;
 };
 
 // Type hash table operations.
@@ -1506,6 +1564,10 @@ protected:
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+  { this->advance_gc_offset(offset); }
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -1583,6 +1645,10 @@ class Float_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+  { this->advance_gc_offset(offset); }
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -1652,6 +1718,10 @@ class Complex_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+  { this->advance_gc_offset(offset); }
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -1701,6 +1771,9 @@ class String_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string* ret) const;
 
@@ -1836,6 +1909,9 @@ class Function_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -1952,6 +2028,9 @@ class Pointer_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2250,6 +2329,9 @@ class Struct_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2392,6 +2474,9 @@ class Array_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2408,6 +2493,12 @@ class Array_type : public Type
   Expression*
   slice_type_descriptor(Gogo*, Named_type*);
 
+  void
+  slice_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+  void
+  array_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   // The type of elements of the array.
   Type* element_type_;
   // The number of elements.  This may be NULL.
@@ -2484,6 +2575,9 @@ class Map_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2570,6 +2664,9 @@ class Channel_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2703,6 +2800,9 @@ class Interface_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
   void
   do_mangled_name(Gogo*, std::string*) const;
 
@@ -2988,6 +3088,10 @@ class Named_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
+              int stack);
+
   void
   do_mangled_name(Gogo*, std::string* ret) const;
 
@@ -3132,6 +3236,11 @@ class Forward_declaration_type : public Type
   void
   do_reflection(Gogo*, std::string*) const;
 
+  void
+  do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
+              int stack_size)
+  { Type::gc_symbol(gogo, this->real_type(), vals, offset, stack_size); }
+
   void
   do_mangled_name(Gogo*, std::string* ret) const;
 
index 74cf2946a016cbb80590c747f7bdb8c8b252dae2..91697c4b56b608f671ed5e4cedb6fe39e3cf0c83 100644 (file)
@@ -255,6 +255,7 @@ type rtype struct {
        hashfn  uintptr // hash function code
        equalfn uintptr // equality function code
 
+       gc            unsafe.Pointer // garbage collection data
        string        *string        // string form; unnecessary  but undeniably useful
        *uncommonType                // (relatively) uncommon fields
        ptrToThis     *rtype         // type for pointer to this type, if used in binary or has methods
@@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype {
        p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
        p.elem = t
 
+       if t.kind&kindNoPointers != 0 {
+               p.gc = unsafe.Pointer(&ptrDataGCProg)
+       } else {
+               p.gc = unsafe.Pointer(&ptrGC{
+                       width:  p.size,
+                       op:     _GC_PTR,
+                       off:    0,
+                       elemgc: t.gc,
+                       end:    _GC_END,
+               })
+       }
+
        q := canonicalize(&p.rtype)
        p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
 
@@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type {
        ch.ptrToThis = nil
        ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
 
+       ch.gc = unsafe.Pointer(&chanGC{
+               width: ch.size,
+               op:    _GC_CHAN_PTR,
+               off:   0,
+               typ:   &ch.rtype,
+               end:   _GC_END,
+       })
+
        // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
-       //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
+       // ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
 
        return cachePut(ckey, &ch.rtype)
 }
@@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type {
        //      width:  unsafe.Sizeof(uintptr(0)),
        //      op:     _GC_PTR,
        //      off:    0,
-       //      elemgc: mt.hmap.gc,
+       //      elemgc: nil,
        //      end:    _GC_END,
        // })
 
+       // TODO(cmang): Generate GC data for Map elements.
+       mt.gc = unsafe.Pointer(&ptrDataGCProg)
+
        // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
        // fail when mt.gc is wrong.
        //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
@@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 
 // Take the GC program for "t" and append it to the GC program "gc".
 func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
-       // p := t.gc
-       var p unsafe.Pointer
+       p := t.gc
        p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
 loop:
        for {
@@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type {
        slice.ptrToThis = nil
        slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
 
+       if typ.size == 0 {
+               slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
+       } else {
+               slice.gc = unsafe.Pointer(&sliceGC{
+                       width:  slice.size,
+                       op:     _GC_SLICE,
+                       off:    0,
+                       elemgc: typ.gc,
+                       end:    _GC_END,
+               })
+       }
+
        // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
-       //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
+       // slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
 
        return cachePut(ckey, &slice.rtype)
 }
index 1211f22257540f5fbff154821233598cd6c346a4..a5ed8af7a85071f6ab38edc90cc004766d587635 100644 (file)
@@ -15,7 +15,7 @@ package runtime
 import "unsafe"
 
 type rtype struct {
-       Kind       uint8
+       kind       uint8
        align      uint8
        fieldAlign uint8
        size       uintptr
@@ -24,6 +24,7 @@ type rtype struct {
        hashfn  func(unsafe.Pointer, uintptr) uintptr
        equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
 
+       gc     unsafe.Pointer
        string *string
        *uncommonType
        ptrToThis *rtype
index 51c2355772d2373d1153c2b96998fe9ad929847f..74e8340059844f0df699b7d6aeef35e7493a679d 100644 (file)
@@ -59,7 +59,7 @@ struct String;
 #define GO_CODE_MASK 0x7f
 
 /* For each Go type the compiler constructs one of these structures.
-   This is used for type reflectin, interfaces, maps, and reference
+   This is used for type reflection, interfaces, maps, and reference
    counting.  */
 
 struct __go_type_descriptor
@@ -93,6 +93,9 @@ struct __go_type_descriptor
      size of this type, and returns whether the values are equal.  */
   _Bool (*__equalfn) (const void *, const void *, uintptr_t);
 
+  /* The garbage collection data. */
+  const uintptr *__gc;
+
   /* A string describing this type.  This is only used for
      debugging.  */
   const struct String *__reflection;
index b71804ac741d9feed2ad6fd50394d60fc08efc1c..67b2999df5db89df3750119ceb01ba251f4d58f3 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "runtime.h"
 #include "go-type.h"
+#include "mgc0.h"
 
 /* A pointer with a zero value.  */
 static void *zero_pointer;
@@ -20,6 +21,9 @@ static void *zero_pointer;
 extern const struct __go_type_descriptor unsafe_Pointer
   __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
 
+extern const uintptr unsafe_Pointer_gc[]
+  __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
+
 /* Used to determine the field alignment.  */
 struct field_align
 {
@@ -35,6 +39,8 @@ static const String reflection_string =
   sizeof REFLECTION - 1
 };
 
+const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END};
+
 const struct __go_type_descriptor unsafe_Pointer =
 {
   /* __code */
@@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer =
   __go_type_hash_identity,
   /* __equalfn */
   __go_type_equal_identity,
+  /* __gc */
+  unsafe_Pointer_gc,
   /* __reflection */
   &reflection_string,
   /* __uncommon */
@@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
     __go_type_hash_identity,
     /* __equalfn */
     __go_type_equal_identity,
+    /* __gc */
+    unsafe_Pointer_gc,
     /* __reflection */
     &preflection_string,
     /* __uncommon */
index 2d6328fbac3bb9c82df8d57dbe51e6f8c259a2cd..6864a833dc46ef2b630747a99edcc1cbd43539f8 100644 (file)
@@ -181,7 +181,7 @@ struct Finalizer
        FuncVal *fn;
        void *arg;
        const struct __go_func_type *ft;
-       const struct __go_ptr_type *ot;
+       const PtrType *ot;
 };
 
 typedef struct FinBlock FinBlock;
@@ -403,8 +403,6 @@ struct BufferList
 };
 static BufferList bufferList[MaxGcproc];
 
-static Type *itabtype;
-
 static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
 
 // flushptrbuf moves data from the PtrTarget buffer to the work buffer.
@@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf)
 // Program that scans the whole block and treats every block element as a potential pointer
 static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
 
-#if 0
 // Hchan program
 static uintptr chanProg[2] = {0, GC_CHAN};
-#endif
 
 // Local variables of a program fragment or loop
 typedef struct Frame Frame;
 struct Frame {
        uintptr count, elemsize, b;
-       uintptr *loop_or_ret;
+       const uintptr *loop_or_ret;
 };
 
 // Sanity check for the derived type info objti.
 static void
 checkptr(void *obj, uintptr objti)
 {
-       uintptr type, tisize, i, x;
+       uintptr *pc1, type, tisize, i, j, x;
+       const uintptr *pc2;
        byte *objstart;
        Type *t;
        MSpan *s;
@@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti)
                (runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
                // Runtime and gc think differently about closures.
                 runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
-#if 0
                pc1 = (uintptr*)objti;
-               pc2 = (uintptr*)t->gc;
+               pc2 = (const uintptr*)t->__gc;
                // A simple best-effort check until first GC_END.
                for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
                        if(pc1[j] != pc2[j]) {
@@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti)
                                runtime_throw("invalid gc type info");
                        }
                }
-#endif
        }
 }                                      
 
@@ -728,11 +723,10 @@ static void
 scanblock(Workbuf *wbuf, bool keepworking)
 {
        byte *b, *arena_start, *arena_used;
-       uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj;
-       uintptr *pc, precise_type, nominal_size;
-#if 0
-       uintptr *chan_ret, chancap;
-#endif
+       uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
+       uintptr precise_type, nominal_size;
+       const uintptr *pc, *chan_ret;
+       uintptr chancap;
        void *obj;
        const Type *t, *et;
        Slice *sliceptr;
@@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
        Scanbuf sbuf;
        Eface *eface;
        Iface *iface;
-#if 0
        Hchan *chan;
-       ChanType *chantype;
-#endif
+       const ChanType *chantype;
        Obj *wp;
 
        if(sizeof(Workbuf) % WorkbufSize != 0)
@@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking)
        sbuf.nobj = nobj;
 
        // (Silence the compiler)
-#if 0
        chan = nil;
        chantype = nil;
        chan_ret = nil;
-#endif
 
        goto next_block;
 
@@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
                        runtime_xadd64(&gcstats.obj.cnt, 1);
                }
 
-               if(ti != 0 && false) {
+               if(ti != 0) {
                        if(Debug > 1) {
                                runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
                        }
@@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                        runtime_throw("invalid gc type info");
                                }
                        }
-               } else if(UseSpanType && false) {
+               } else if(UseSpanType) {
                        if(CollectStats)
                                runtime_xadd64(&gcstats.obj.notype, 1);
 
-#if 0
                        type = runtime_gettype(b);
                        if(type != 0) {
                                if(CollectStats)
@@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                t = (Type*)(type & ~(uintptr)(PtrSize-1));
                                switch(type & (PtrSize-1)) {
                                case TypeInfo_SingleObject:
-                                       pc = (uintptr*)t->gc;
+                                       pc = (const uintptr*)t->__gc;
                                        precise_type = true;  // type information about 'b' is precise
                                        stack_top.count = 1;
                                        stack_top.elemsize = pc[0];
                                        break;
                                case TypeInfo_Array:
-                                       pc = (uintptr*)t->gc;
+                                       pc = (const uintptr*)t->__gc;
                                        if(pc[0] == 0)
                                                goto next_block;
                                        precise_type = true;  // type information about 'b' is precise
@@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                        break;
                                case TypeInfo_Chan:
                                        chan = (Hchan*)b;
-                                       chantype = (ChanType*)t;
+                                       chantype = (const ChanType*)t;
                                        chan_ret = nil;
                                        pc = chanProg;
                                        break;
@@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                if(Debug > 1)
                                        runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
                        }
-#endif
                } else {
                        pc = defaultProg;
                        if(Debug > 1)
@@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
 
                        // eface->__object
                        if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
-                               if(t->__size <= sizeof(void*)) {
+                               if(__go_is_pointer_type(t)) {
                                        if((t->__code & KindNoPointers))
                                                continue;
 
@@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                                // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
                                                et = ((const PtrType*)t)->elem;
                                                if(!(et->__code & KindNoPointers))
-                                                       // objti = (uintptr)((const PtrType*)t)->elem->gc;
-                                                       objti = 0;
+                                                       objti = (uintptr)((const PtrType*)t)->elem->__gc;
                                        }
                                } else {
                                        obj = eface->__object;
-                                       // objti = (uintptr)t->gc;
-                                       objti = 0;
+                                       objti = (uintptr)t->__gc;
                                }
                        }
                        break;
@@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking)
                        
                        // iface->tab
                        if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) {
-                               *sbuf.ptr.pos++ = (PtrTarget){iface->tab, /* (uintptr)itabtype->gc */ 0};
+                               *sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0};
                                if(sbuf.ptr.pos == sbuf.ptr.end)
                                        flushptrbuf(&sbuf);
                        }
 
                        // iface->data
                        if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
-                               // t = iface->tab->type;
-                               t = nil;
-                               if(t->__size <= sizeof(void*)) {
+                               t = (const Type*)iface->tab[0];
+                               if(__go_is_pointer_type(t)) {
                                        if((t->__code & KindNoPointers))
                                                continue;
 
@@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                                // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
                                                et = ((const PtrType*)t)->elem;
                                                if(!(et->__code & KindNoPointers))
-                                                       // objti = (uintptr)((const PtrType*)t)->elem->gc;
-                                                       objti = 0;
+                                                       objti = (uintptr)((const PtrType*)t)->elem->__gc;
                                        }
                                } else {
                                        obj = iface->__object;
-                                       // objti = (uintptr)t->gc;
-                                       objti = 0;
+                                       objti = (uintptr)t->__gc;
                                }
                        }
                        break;
@@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
                        // Stack push.
                        *stack_ptr-- = stack_top;
                        stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
-                       pc = (uintptr*)((byte*)pc + *(int32*)(pc+2));  // target of the CALL instruction
+                       pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2));  // target of the CALL instruction
                        continue;
 
                case GC_REGION:
@@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                flushobjbuf(&sbuf);
                        continue;
 
-#if 0
                case GC_CHAN_PTR:
                        chan = *(Hchan**)(stack_top.b + pc[1]);
                        if(Debug > 2 && chan != nil)
@@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                        // in-use part of the circular buffer is scanned.
                                        // (Channel routines zero the unused part, so the current
                                        // code does not lead to leaks, it's just a little inefficient.)
-                                       *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size,
-                                               (uintptr)chantype->elem->gc | PRECISE | LOOP};
+                                       *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
+                                               (uintptr)chantype->elem->__gc | PRECISE | LOOP};
                                        if(sbuf.obj.pos == sbuf.obj.end)
                                                flushobjbuf(&sbuf);
                                }
@@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
                                goto next_block;
                        pc = chan_ret;
                        continue;
-#endif
 
                default:
                        runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
@@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s)
 }
 
 // State of background sweep.
-// Pretected by gclock.
+// Protected by gclock.
 static struct
 {
        G*      g;
@@ -2260,12 +2241,6 @@ gc(struct gc_args *args)
                work.markfor = runtime_parforalloc(MaxGcproc);
        m->locks--;
 
-       if(itabtype == nil) {
-               // get C pointer to the Go type "itab"
-               // runtime_gc_itab_ptr(&eface);
-               // itabtype = ((PtrType*)eface.__type_descriptor)->elem;
-       }
-
        t1 = 0;
        if(runtime_debug.gctrace)
                t1 = runtime_nanotime();
index 6650be1b3d349488260b22c10bfd060aacd2a0ba..c96290a0b066b7fc43693a64661537e58fa986eb 100644 (file)
@@ -800,7 +800,7 @@ uintptr     runtime_memlimit(void);
 
 enum
 {
-       UseSpanType = 0,
+       UseSpanType = 1,
 };
 
 #define runtime_setitimer setitimer