compiler: add slice initializers to the GC root list
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 1 Dec 2016 19:54:36 +0000 (19:54 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 1 Dec 2016 19:54:36 +0000 (19:54 +0000)
    As of https://golang.org/cl/32917 we can put slice initializers in the
    .data section.  The program can still change the values in those
    slices.  That means that if the slice elements can contain pointers,
    we need to register the entire initializer as a GC root.

    This would be straightforward except that we only have a Bexpression
    for the slice initializer, not an Expression.  So introduce a
    Backend_expression type that wraps a Bexpression as an Expression.

    The test case for this is https://golang.org/cl/33790.

    Reviewed-on: https://go-review.googlesource.com/33792

From-SVN: r243129

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h

index 8f5f542fcebf6183c2650d5d5a83c23e4078c874..5529002b09003123e03f0a4c7d833589e9c1824a 100644 (file)
@@ -1,4 +1,4 @@
-97b949f249515a61d3c09e9e06f08c8af189e967
+b7bad96ce0af50a1129eaab9aa110d68a601917b
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 0ab672608753e2b616f2ead6ccb5faa69fc891e2..9740d324a865b963f7dbff989f7b57abda47a8aa 100644 (file)
@@ -4295,6 +4295,20 @@ Unary_expression::do_get_backend(Translate_context* context)
                                                      true, copy_to_heap, false,
                                                      bexpr);
          bexpr = gogo->backend()->var_expression(implicit, loc);
+
+         // If we are not copying a slice initializer to the heap,
+         // then it can be changed by the program, so if it can
+         // contain pointers we must register it as a GC root.
+         if (this->is_slice_init_
+             && !copy_to_heap
+             && this->expr_->type()->has_pointer())
+           {
+             Bexpression* root =
+               gogo->backend()->var_expression(implicit, loc);
+             root = gogo->backend()->address_expression(root, loc);
+             Type* type = Type::make_pointer_type(this->expr_->type());
+             gogo->add_gc_root(Expression::make_backend(root, type, loc));
+           }
        }
       else if ((this->expr_->is_composite_literal()
                || this->expr_->string_expression() != NULL)
@@ -15433,6 +15447,28 @@ Expression::make_compound(Expression* init, Expression* expr, Location location)
   return new Compound_expression(init, expr, location);
 }
 
+// Class Backend_expression.
+
+int
+Backend_expression::do_traverse(Traverse*)
+{
+  return TRAVERSE_CONTINUE;
+}
+
+void
+Backend_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "backend_expression<";
+  ast_dump_context->dump_type(this->type_);
+  ast_dump_context->ostream() << ">";
+}
+
+Expression*
+Expression::make_backend(Bexpression* bexpr, Type* type, Location location)
+{
+  return new Backend_expression(bexpr, type, location);
+}
+
 // Import an expression.  This comes at the end in order to see the
 // various class definitions.
 
index 96d314ffbda0269ef06f4ecb5c2bb804f170a3cf..f31d4a6d0077b65a15fbd1ff526e50cd8d4292f5 100644 (file)
@@ -137,7 +137,8 @@ class Expression
     EXPRESSION_STRUCT_FIELD_OFFSET,
     EXPRESSION_LABEL_ADDR,
     EXPRESSION_CONDITIONAL,
-    EXPRESSION_COMPOUND
+    EXPRESSION_COMPOUND,
+    EXPRESSION_BACKEND
   };
 
   Expression(Expression_classification, Location);
@@ -485,6 +486,10 @@ class Expression
   static Expression*
   make_compound(Expression*, Expression*, Location);
 
+  // Make a backend expression.
+  static Expression*
+  make_backend(Bexpression*, Type*, Location);
+
   // Return the expression classification.
   Expression_classification
   classification() const
@@ -3825,6 +3830,54 @@ class Compound_expression : public Expression
   Expression* expr_;
 };
 
+// A backend expression.  This is a backend expression wrapped in an
+// Expression, for convenience during backend generation.
+
+class Backend_expression : public Expression
+{
+ public:
+  Backend_expression(Bexpression* bexpr, Type* type, Location location)
+    : Expression(EXPRESSION_BACKEND, location), bexpr_(bexpr), type_(type)
+  {}
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  // For now these are always valid static initializers.  If that
+  // changes we can change this.
+  bool
+  do_is_static_initializer() const
+  { return true; }
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  {
+    return new Backend_expression(this->bexpr_, this->type_, this->location());
+  }
+
+  Bexpression*
+  do_get_backend(Translate_context*)
+  { return this->bexpr_; }
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The backend expression we are wrapping.
+  Bexpression* bexpr_;
+  // The type of the expression;
+  Type* type_;
+};
+
 // A numeric constant.  This is used both for untyped constants and
 // for constants that have a type.
 
index b671ce5bced81cbfc828c2d1cd34c8b614ec354b..d685bcaeef668a5f37debbb13c68f601083f13ab 100644 (file)
@@ -54,7 +54,9 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
     interface_types_(),
     specific_type_functions_(),
     specific_type_functions_are_written_(false),
-    named_types_are_converted_(false)
+    named_types_are_converted_(false),
+    analysis_sets_(),
+    gc_roots_()
 {
   const Location loc = Linemap::predeclared_location();
 
@@ -750,10 +752,9 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
 
   Expression_list* roots_init = new Expression_list();
 
-  size_t i = 0;
   for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
        p != var_gc.end();
-       ++p, ++i)
+       ++p)
     {
       Expression_list* init = new Expression_list();
 
@@ -772,6 +773,27 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
       roots_init->push_back(root_ctor);
     }
 
+  for (std::vector<Expression*>::const_iterator p = this->gc_roots_.begin();
+       p != this->gc_roots_.end();
+       ++p)
+    {
+      Expression_list *init = new Expression_list();
+
+      Expression* expr = *p;
+      Location eloc = expr->location();
+      init->push_back(expr);
+
+      Type* type = expr->type()->points_to();
+      go_assert(type != NULL);
+      Expression* size =
+       Expression::make_type_info(type, Expression::TYPE_INFO_SIZE);
+      init->push_back(size);
+
+      Expression* root_ctor =
+       Expression::make_struct_composite_literal(root_type, init, eloc);
+      roots_init->push_back(root_ctor);
+    }
+
   // The list ends with a NULL entry.
 
   Expression_list* null_init = new Expression_list();
index 62bbf9e11ae3aa86883bb55c5712aa4a77d10bcf..7ddb3ce3cedf13b64635ca2dc386f5d298ed1bb0 100644 (file)
@@ -19,6 +19,7 @@ class Typed_identifier;
 class Typed_identifier_list;
 class Function_type;
 class Expression;
+class Expression_list;
 class Statement;
 class Temporary_statement;
 class Block;
@@ -556,6 +557,15 @@ class Gogo
   specific_type_functions_are_written() const
   { return this->specific_type_functions_are_written_; }
 
+  // Add a pointer that needs to be added to the list of objects
+  // traversed by the garbage collector.  This should be an expression
+  // of pointer type that points to static storage.  It's not
+  // necessary to add global variables to this list, just global
+  // variable initializers that would otherwise not be seen.
+  void
+  add_gc_root(Expression* expr)
+  { this->gc_roots_.push_back(expr); }
+
   // Traverse the tree.  See the Traverse class.
   void
   traverse(Traverse*);
@@ -892,6 +902,8 @@ class Gogo
   // A list containing groups of possibly mutually recursive functions to be
   // considered during escape analysis.
   std::vector<Analysis_set> analysis_sets_;
+  // A list of objects to add to the GC roots.
+  std::vector<Expression*> gc_roots_;
 };
 
 // A block of statements.