github.com/kidsbmilk/gofronted_all@v0.0.0-20220701224323-6479d5976c5d/go/wb.cc (about)

     1  // wb.cc -- Add write barriers as needed.
     2  
     3  // Copyright 2017 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  #include "go-system.h"
     8  
     9  #include "go-c.h"
    10  #include "go-diagnostics.h"
    11  #include "operator.h"
    12  #include "lex.h"
    13  #include "types.h"
    14  #include "expressions.h"
    15  #include "statements.h"
    16  #include "runtime.h"
    17  #include "gogo.h"
    18  
    19  // Mark variables whose addresses are taken and do some other
    20  // cleanups.  This has to be done before the write barrier pass and
    21  // after the escape analysis pass.  It would be nice to do this
    22  // elsewhere but there isn't an obvious place.
    23  
    24  class Mark_address_taken : public Traverse
    25  {
    26   public:
    27    Mark_address_taken(Gogo* gogo)
    28      : Traverse(traverse_functions
    29  	       | traverse_statements
    30  	       | traverse_expressions),
    31        gogo_(gogo), function_(NULL)
    32    { }
    33  
    34    int
    35    function(Named_object*);
    36  
    37    int
    38    statement(Block*, size_t*, Statement*);
    39  
    40    int
    41    expression(Expression**);
    42  
    43   private:
    44    // General IR.
    45    Gogo* gogo_;
    46    // The function we are traversing.
    47    Named_object* function_;
    48  };
    49  
    50  // Record a function.
    51  
    52  int
    53  Mark_address_taken::function(Named_object* no)
    54  {
    55    go_assert(this->function_ == NULL);
    56    this->function_ = no;
    57    int t = no->func_value()->traverse(this);
    58    this->function_ = NULL;
    59  
    60    if (t == TRAVERSE_EXIT)
    61      return t;
    62    return TRAVERSE_SKIP_COMPONENTS;
    63  }
    64  
    65  // Traverse a statement.
    66  
    67  int
    68  Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s)
    69  {
    70    // If this is an assignment of the form s = append(s, ...), expand
    71    // it now, so that we can assign it to the left hand side in the
    72    // middle of the expansion and possibly skip a write barrier.
    73    Assignment_statement* as = s->assignment_statement();
    74    if (as != NULL && !as->lhs()->is_sink_expression())
    75      {
    76        Call_expression* rce = as->rhs()->call_expression();
    77        if (rce != NULL
    78  	  && rce->builtin_call_expression() != NULL
    79  	  && (rce->builtin_call_expression()->code()
    80  	      == Builtin_call_expression::BUILTIN_APPEND)
    81            && Expression::is_same_variable(as->lhs(), rce->args()->front()))
    82  	{
    83  	  Statement_inserter inserter = Statement_inserter(block, pindex);
    84  	  Expression* a =
    85  	    rce->builtin_call_expression()->flatten_append(this->gogo_,
    86  							   this->function_,
    87  							   &inserter,
    88  							   as->lhs(),
    89  							   block);
    90  	  go_assert(a == NULL);
    91  	  // That does the assignment, so remove this statement.
    92  	  Expression* e = Expression::make_boolean(true, s->location());
    93  	  Statement* dummy = Statement::make_statement(e, true);
    94  	  block->replace_statement(*pindex, dummy);
    95  	}
    96      }
    97    return TRAVERSE_CONTINUE;
    98  }
    99  
   100  // Mark variable addresses taken.
   101  
   102  int
   103  Mark_address_taken::expression(Expression** pexpr)
   104  {
   105    Expression* expr = *pexpr;
   106    Unary_expression* ue = expr->unary_expression();
   107    if (ue != NULL)
   108      ue->check_operand_address_taken(this->gogo_);
   109  
   110    Array_index_expression* aie = expr->array_index_expression();
   111    if (aie != NULL
   112        && aie->end() != NULL
   113        && !aie->array()->type()->is_slice_type())
   114      {
   115        // Slice of an array. The escape analysis models this with
   116        // a child Node representing the address of the array.
   117        bool escapes = false;
   118        Node* n = Node::make_node(expr);
   119        if (n->child() == NULL
   120            || (n->child()->encoding() & ESCAPE_MASK) != Node::ESCAPE_NONE)
   121          escapes = true;
   122        aie->array()->address_taken(escapes);
   123      }
   124  
   125    if (expr->allocation_expression() != NULL)
   126      {
   127        Node* n = Node::make_node(expr);
   128        if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
   129          expr->allocation_expression()->set_allocate_on_stack();
   130      }
   131    if (expr->heap_expression() != NULL)
   132      {
   133        Node* n = Node::make_node(expr);
   134        if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
   135          expr->heap_expression()->set_allocate_on_stack();
   136      }
   137    if (expr->slice_literal() != NULL)
   138      {
   139        Node* n = Node::make_node(expr);
   140        if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
   141          expr->slice_literal()->set_storage_does_not_escape();
   142      }
   143  
   144    // Rewrite non-escaping makeslice with constant size to stack allocation.
   145    Slice_value_expression* sve = expr->slice_value_expression();
   146    if (sve != NULL)
   147      {
   148        std::pair<Call_expression*, Temporary_statement*> p =
   149          Expression::find_makeslice_call(sve);
   150        Call_expression* call = p.first;
   151        Temporary_statement* ts = p.second;
   152        if (call != NULL
   153  	  && Node::make_node(call)->encoding() == Node::ESCAPE_NONE)
   154          {
   155            Expression* len_arg = call->args()->at(1);
   156            Expression* cap_arg = call->args()->at(2);
   157            Numeric_constant nclen;
   158            Numeric_constant nccap;
   159            unsigned long vlen;
   160            unsigned long vcap;
   161            if (len_arg->numeric_constant_value(&nclen)
   162                && cap_arg->numeric_constant_value(&nccap)
   163                && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID
   164                && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID)
   165              {
   166  	      // Stack allocate an array and make a slice value from it.
   167                Location loc = expr->location();
   168                Type* elmt_type = expr->type()->array_type()->element_type();
   169                Expression* len_expr =
   170                  Expression::make_integer_ul(vcap, cap_arg->type(), loc);
   171                Type* array_type = Type::make_array_type(elmt_type, len_expr);
   172                Expression* alloc = Expression::make_allocation(array_type, loc);
   173                alloc->allocation_expression()->set_allocate_on_stack();
   174  	      Type* ptr_type = Type::make_pointer_type(elmt_type);
   175  	      Expression* ptr = Expression::make_unsafe_cast(ptr_type, alloc,
   176  							     loc);
   177  	      Expression* slice =
   178  		Expression::make_slice_value(expr->type(), ptr, len_arg,
   179  					     cap_arg, loc);
   180                *pexpr = slice;
   181                if (ts != NULL && ts->uses() == 1)
   182                  ts->set_init(Expression::make_nil(loc));
   183              }
   184          }
   185      }
   186    return TRAVERSE_CONTINUE;
   187  }
   188  
   189  // Check variables and closures do not escape when compiling runtime.
   190  
   191  class Check_escape : public Traverse
   192  {
   193   public:
   194    Check_escape(Gogo* gogo)
   195      : Traverse(traverse_expressions | traverse_variables),
   196        gogo_(gogo)
   197    { }
   198  
   199    int
   200    expression(Expression**);
   201  
   202    int
   203    variable(Named_object*);
   204  
   205   private:
   206    Gogo* gogo_;
   207  };
   208  
   209  int
   210  Check_escape::variable(Named_object* no)
   211  {
   212    if ((no->is_variable() && no->var_value()->is_in_heap())
   213        || (no->is_result_variable()
   214            && no->result_var_value()->is_in_heap()))
   215      go_error_at(no->location(),
   216                  "%s escapes to heap, not allowed in runtime",
   217                  no->message_name().c_str());
   218    return TRAVERSE_CONTINUE;
   219  }
   220  
   221  int
   222  Check_escape::expression(Expression** pexpr)
   223  {
   224    Expression* expr = *pexpr;
   225    Func_expression* fe = expr->func_expression();
   226    if (fe != NULL && fe->closure() != NULL)
   227      {
   228        Node* n = Node::make_node(expr);
   229        if (n->encoding() == Node::ESCAPE_HEAP)
   230          go_error_at(expr->location(),
   231                      "heap-allocated closure, not allowed in runtime");
   232      }
   233    return TRAVERSE_CONTINUE;
   234  }
   235  
   236  // Collect all writebarrierrec functions.  This is used when compiling
   237  // the runtime package, to propagate //go:nowritebarrierrec.
   238  
   239  class Collect_writebarrierrec_functions : public Traverse
   240  {
   241   public:
   242    Collect_writebarrierrec_functions(std::vector<Named_object*>* worklist)
   243      : Traverse(traverse_functions),
   244        worklist_(worklist)
   245    { }
   246  
   247   private:
   248    int
   249    function(Named_object*);
   250  
   251    // The collected functions are put here.
   252    std::vector<Named_object*>* worklist_;
   253  };
   254  
   255  int
   256  Collect_writebarrierrec_functions::function(Named_object* no)
   257  {
   258    if (no->is_function()
   259        && no->func_value()->enclosing() == NULL
   260        && (no->func_value()->pragmas() & GOPRAGMA_NOWRITEBARRIERREC) != 0)
   261      {
   262        go_assert((no->func_value()->pragmas() & GOPRAGMA_MARK) == 0);
   263        this->worklist_->push_back(no);
   264      }
   265    return TRAVERSE_CONTINUE;
   266  }
   267  
   268  // Collect all callees of this function.  We only care about locally
   269  // defined, known, functions.
   270  
   271  class Collect_callees : public Traverse
   272  {
   273   public:
   274    Collect_callees(std::vector<Named_object*>* worklist)
   275      : Traverse(traverse_expressions),
   276        worklist_(worklist)
   277    { }
   278  
   279   private:
   280    int
   281    expression(Expression**);
   282  
   283    // The collected callees are put here.
   284    std::vector<Named_object*>* worklist_;
   285  };
   286  
   287  int
   288  Collect_callees::expression(Expression** pexpr)
   289  {
   290    Call_expression* ce = (*pexpr)->call_expression();
   291    if (ce != NULL)
   292      {
   293        Func_expression* fe = ce->fn()->func_expression();
   294        if (fe != NULL)
   295  	{
   296  	  Named_object* no = fe->named_object();
   297  	  if (no->package() == NULL && no->is_function())
   298  	    {
   299  	      // The function runtime.systemstack is special, in that
   300  	      // it is a common way to call a function in the runtime:
   301  	      // mark its argument if we can.
   302  	      if (Gogo::unpack_hidden_name(no->name()) != "systemstack")
   303  		this->worklist_->push_back(no);
   304  	      else if (ce->args()->size() > 0)
   305  		{
   306  		  fe = ce->args()->front()->func_expression();
   307  		  if (fe != NULL)
   308  		    {
   309  		      no = fe->named_object();
   310  		      if (no->package() == NULL && no->is_function())
   311  			this->worklist_->push_back(no);
   312  		    }
   313  		}
   314  	    }
   315  	}
   316      }
   317    return TRAVERSE_CONTINUE;
   318  }
   319  
   320  // When compiling the runtime package, propagate //go:nowritebarrierrec
   321  // annotations.  A function marked as //go:nowritebarrierrec does not
   322  // permit write barriers, and also all the functions that it calls,
   323  // recursively, do not permit write barriers.  Except that a
   324  // //go:yeswritebarrierrec annotation permits write barriers even if
   325  // called by a //go:nowritebarrierrec function.  Here we turn
   326  // //go:nowritebarrierrec into //go:nowritebarrier, as appropriate.
   327  
   328  void
   329  Gogo::propagate_writebarrierrec()
   330  {
   331    std::vector<Named_object*> worklist;
   332    Collect_writebarrierrec_functions cwf(&worklist);
   333    this->traverse(&cwf);
   334  
   335    Collect_callees cc(&worklist);
   336  
   337    while (!worklist.empty())
   338      {
   339        Named_object* no = worklist.back();
   340        worklist.pop_back();
   341  
   342        unsigned int pragmas = no->func_value()->pragmas();
   343        if ((pragmas & GOPRAGMA_MARK) != 0)
   344  	{
   345  	  // We've already seen this function.
   346  	  continue;
   347  	}
   348        if ((pragmas & GOPRAGMA_YESWRITEBARRIERREC) != 0)
   349  	{
   350  	  // We don't want to propagate //go:nowritebarrierrec into
   351  	  // this function or it's callees.
   352  	  continue;
   353  	}
   354  
   355        no->func_value()->set_pragmas(pragmas
   356  				    | GOPRAGMA_NOWRITEBARRIER
   357  				    | GOPRAGMA_MARK);
   358  
   359        no->func_value()->traverse(&cc);
   360      }
   361  }
   362  
   363  // Add write barriers to the IR.  This are required by the concurrent
   364  // garbage collector.  A write barrier is needed for any write of a
   365  // pointer into memory controlled by the garbage collector.  Write
   366  // barriers are not required for writes to local variables that live
   367  // on the stack.  Write barriers are only required when the runtime
   368  // enables them, which can be checked using a run time check on
   369  // runtime.writeBarrier.enabled.
   370  //
   371  // Essentially, for each assignment A = B, where A is or contains a
   372  // pointer, and where A is not, or at any rate may not be, a stack
   373  // variable, we rewrite it into
   374  //     if runtime.writeBarrier.enabled {
   375  //         typedmemmove(typeof(A), &A, &B)
   376  //     } else {
   377  //         A = B
   378  //     }
   379  //
   380  // The test of runtime.writeBarrier.Enabled is implemented by treating
   381  // the variable as a *uint32, and testing *runtime.writeBarrier != 0.
   382  // This is compatible with the definition in the runtime package.
   383  //
   384  // For types that are pointer shared (pointers, maps, chans, funcs),
   385  // we replaced the call to typedmemmove with gcWriteBarrier(&A, B).
   386  // As far as the GC is concerned, all pointers are the same, so it
   387  // doesn't need the type descriptor.
   388  //
   389  // There are possible optimizations that are not implemented.
   390  //
   391  // runtime.writeBarrier can only change when the goroutine is
   392  // preempted, which in practice means when a call is made into the
   393  // runtime package, so we could optimize by only testing it once
   394  // between function calls.
   395  //
   396  // A slice could be handled with a call to gcWriteBarrier plus two
   397  // integer moves.
   398  
   399  // Traverse the IR adding write barriers.
   400  
   401  class Write_barriers : public Traverse
   402  {
   403   public:
   404    Write_barriers(Gogo* gogo)
   405      : Traverse(traverse_functions
   406  	       | traverse_blocks
   407  	       | traverse_variables
   408  	       | traverse_statements),
   409        gogo_(gogo), function_(NULL), statements_added_(),
   410        nonwb_pointers_()
   411    { }
   412  
   413    int
   414    function(Named_object*);
   415  
   416    int
   417    block(Block*);
   418  
   419    int
   420    variable(Named_object*);
   421  
   422    int
   423    statement(Block*, size_t* pindex, Statement*);
   424  
   425   private:
   426    // General IR.
   427    Gogo* gogo_;
   428    // Current function.
   429    Function* function_;
   430    // Statements introduced.
   431    Statement_inserter::Statements statements_added_;
   432    // Within a single block, pointer variables that point to values
   433    // that do not need write barriers.
   434    Unordered_set(const Named_object*) nonwb_pointers_;
   435  };
   436  
   437  // Traverse a function.  Just record it for later.
   438  
   439  int
   440  Write_barriers::function(Named_object* no)
   441  {
   442    go_assert(this->function_ == NULL);
   443    this->function_ = no->func_value();
   444    int t = this->function_->traverse(this);
   445    this->function_ = NULL;
   446  
   447    if (t == TRAVERSE_EXIT)
   448      return t;
   449    return TRAVERSE_SKIP_COMPONENTS;
   450  }
   451  
   452  // Traverse a block.  Clear anything we know about local pointer
   453  // variables.
   454  
   455  int
   456  Write_barriers::block(Block*)
   457  {
   458    this->nonwb_pointers_.clear();
   459    return TRAVERSE_CONTINUE;
   460  }
   461  
   462  // Insert write barriers for a global variable: ensure that variable
   463  // initialization is handled correctly.  This is rarely needed, since
   464  // we currently don't enable background GC until after all global
   465  // variables are initialized.  But we do need this if an init function
   466  // calls runtime.GC.
   467  
   468  int
   469  Write_barriers::variable(Named_object* no)
   470  {
   471    // We handle local variables in the variable declaration statement.
   472    // We only have to handle global variables here.
   473    if (!no->is_variable())
   474      return TRAVERSE_CONTINUE;
   475    Variable* var = no->var_value();
   476    if (!var->is_global())
   477      return TRAVERSE_CONTINUE;
   478  
   479    // Nothing to do if there is no initializer.
   480    Expression* init = var->init();
   481    if (init == NULL)
   482      return TRAVERSE_CONTINUE;
   483  
   484    // Nothing to do for variables that do not contain any pointers.
   485    if (!var->type()->has_pointer())
   486      return TRAVERSE_CONTINUE;
   487  
   488    // Nothing to do if the initializer is static.
   489    init = Expression::make_cast(var->type(), init, var->location());
   490    if (!var->has_pre_init() && init->is_static_initializer())
   491      return TRAVERSE_CONTINUE;
   492  
   493    // Nothing to do for a type that can not be in the heap, or a
   494    // pointer to a type that can not be in the heap.
   495    if (!var->type()->in_heap())
   496      return TRAVERSE_CONTINUE;
   497    if (var->type()->points_to() != NULL && !var->type()->points_to()->in_heap())
   498      return TRAVERSE_CONTINUE;
   499  
   500    // Otherwise change the initializer into a pre_init assignment
   501    // statement with a write barrier.
   502  
   503    // We can't check for a dependency of the variable on itself after
   504    // we make this change, because the preinit statement will always
   505    // depend on the variable (since it assigns to it).  So check for a
   506    // self-dependency now.
   507    this->gogo_->check_self_dep(no);
   508  
   509    // Replace the initializer.
   510    Location loc = init->location();
   511    Expression* ref = Expression::make_var_reference(no, loc);
   512  
   513    Statement_inserter inserter(this->gogo_, var, &this->statements_added_);
   514    Statement* s = this->gogo_->assign_with_write_barrier(NULL, NULL, &inserter,
   515  							ref, init, loc);
   516    this->statements_added_.insert(s);
   517  
   518    var->add_preinit_statement(this->gogo_, s);
   519    var->clear_init();
   520  
   521    return TRAVERSE_CONTINUE;
   522  }
   523  
   524  // Insert write barriers for statements.
   525  
   526  int
   527  Write_barriers::statement(Block* block, size_t* pindex, Statement* s)
   528  {
   529    if (this->statements_added_.find(s) != this->statements_added_.end())
   530      return TRAVERSE_SKIP_COMPONENTS;
   531  
   532    switch (s->classification())
   533      {
   534      default:
   535        break;
   536  
   537      case Statement::STATEMENT_VARIABLE_DECLARATION:
   538        {
   539  	Variable_declaration_statement* vds =
   540  	  s->variable_declaration_statement();
   541  	Named_object* no = vds->var();
   542  	Variable* var = no->var_value();
   543  
   544  	// We may need to emit a write barrier for the initialization
   545  	// of the variable.
   546  
   547  	// Nothing to do for a variable with no initializer.
   548  	Expression* init = var->init();
   549  	if (init == NULL)
   550  	  break;
   551  
   552  	// Nothing to do if the variable is not in the heap.  Only
   553  	// local variables get declaration statements, and local
   554  	// variables on the stack do not require write barriers.
   555  	if (!var->is_in_heap())
   556            {
   557  	    // If this is a pointer variable, and assigning through
   558  	    // the initializer does not require a write barrier,
   559  	    // record that fact.
   560  	    if (var->type()->points_to() != NULL
   561  		&& this->gogo_->is_nonwb_pointer(init, &this->nonwb_pointers_))
   562  	      this->nonwb_pointers_.insert(no);
   563  
   564  	    break;
   565            }
   566  
   567  	// Nothing to do if the variable does not contain any pointers.
   568  	if (!var->type()->has_pointer())
   569  	  break;
   570  
   571  	// Nothing to do for a type that can not be in the heap, or a
   572  	// pointer to a type that can not be in the heap.
   573  	if (!var->type()->in_heap())
   574  	  break;
   575  	if (var->type()->points_to() != NULL
   576  	    && !var->type()->points_to()->in_heap())
   577  	  break;
   578  
   579  	// Otherwise initialize the variable with a write barrier.
   580  
   581  	Function* function = this->function_;
   582  	Location loc = init->location();
   583  	Statement_inserter inserter(block, pindex, &this->statements_added_);
   584  
   585  	// Insert the variable declaration statement with no
   586  	// initializer, so that the variable exists.
   587  	var->clear_init();
   588  	inserter.insert(s);
   589  
   590  	// Create a statement that initializes the variable with a
   591  	// write barrier.
   592  	Expression* ref = Expression::make_var_reference(no, loc);
   593  	Statement* assign = this->gogo_->assign_with_write_barrier(function,
   594  								   block,
   595  								   &inserter,
   596  								   ref, init,
   597  								   loc);
   598          this->statements_added_.insert(assign);
   599  
   600  	// Replace the old variable declaration statement with the new
   601  	// initialization.
   602  	block->replace_statement(*pindex, assign);
   603        }
   604        break;
   605  
   606      case Statement::STATEMENT_ASSIGNMENT:
   607        {
   608  	Assignment_statement* as = s->assignment_statement();
   609  
   610  	Expression* lhs = as->lhs();
   611  	Expression* rhs = as->rhs();
   612  
   613  	// Keep track of variables whose values do not escape.
   614  	Var_expression* lhsve = lhs->var_expression();
   615  	if (lhsve != NULL && lhsve->type()->points_to() != NULL)
   616  	  {
   617  	    Named_object* no = lhsve->named_object();
   618  	    if (this->gogo_->is_nonwb_pointer(rhs, &this->nonwb_pointers_))
   619  	      this->nonwb_pointers_.insert(no);
   620  	    else
   621  	      this->nonwb_pointers_.erase(no);
   622  	  }
   623  
   624  	if (as->omit_write_barrier())
   625  	  break;
   626  
   627  	// We may need to emit a write barrier for the assignment.
   628  
   629  	if (!this->gogo_->assign_needs_write_barrier(lhs,
   630  						     &this->nonwb_pointers_))
   631  	  break;
   632  
   633  	// Change the assignment to use a write barrier.
   634  	Function* function = this->function_;
   635  	Location loc = as->location();
   636  	Statement_inserter inserter =
   637              Statement_inserter(block, pindex, &this->statements_added_);
   638  	Statement* assign = this->gogo_->assign_with_write_barrier(function,
   639  								   block,
   640  								   &inserter,
   641  								   lhs, rhs,
   642  								   loc);
   643          this->statements_added_.insert(assign);
   644  	block->replace_statement(*pindex, assign);
   645        }
   646        break;
   647      }
   648  
   649    return TRAVERSE_CONTINUE;
   650  }
   651  
   652  // The write barrier pass.
   653  
   654  void
   655  Gogo::add_write_barriers()
   656  {
   657    if (saw_errors())
   658      return;
   659  
   660    Mark_address_taken mat(this);
   661    this->traverse(&mat);
   662  
   663    if (this->compiling_runtime() && this->package_name() == "runtime")
   664      {
   665        this->propagate_writebarrierrec();
   666  
   667        Check_escape chk(this);
   668        this->traverse(&chk);
   669      }
   670  
   671    Write_barriers wb(this);
   672    this->traverse(&wb);
   673  }
   674  
   675  // Return the runtime.writeBarrier variable.
   676  
   677  Named_object*
   678  Gogo::write_barrier_variable()
   679  {
   680    static Named_object* write_barrier_var;
   681    if (write_barrier_var == NULL)
   682      {
   683        Location bloc = Linemap::predeclared_location();
   684  
   685        Type* bool_type = Type::lookup_bool_type();
   686        Array_type* pad_type =
   687  	Type::make_array_type(Type::lookup_integer_type("byte"),
   688  			      Expression::make_integer_ul(3, NULL, bloc));
   689        Type* uint64_type = Type::lookup_integer_type("uint64");
   690        Type* wb_type = Type::make_builtin_struct_type(5,
   691  						     "enabled", bool_type,
   692  						     "pad", pad_type,
   693  						     "needed", bool_type,
   694  						     "cgo", bool_type,
   695  						     "alignme", uint64_type);
   696  
   697        Variable* var = new Variable(wb_type, NULL,
   698  				    true, false, false, bloc);
   699  
   700        bool add_to_globals;
   701        Package* package = this->add_imported_package("runtime", "_", false,
   702  						    "runtime", "runtime",
   703  						    bloc, &add_to_globals);
   704        write_barrier_var = Named_object::make_variable("writeBarrier",
   705  						      package, var);
   706      }
   707  
   708    return write_barrier_var;
   709  }
   710  
   711  // Return whether an assignment that sets LHS needs a write barrier.
   712  // NONWB_POINTERS is a set of variables that point to values that do
   713  // not need write barriers.
   714  
   715  bool
   716  Gogo::assign_needs_write_barrier(
   717      Expression* lhs,
   718      Unordered_set(const Named_object*)* nonwb_pointers)
   719  {
   720    // Nothing to do if the variable does not contain any pointers.
   721    if (!lhs->type()->has_pointer())
   722      return false;
   723  
   724    // An assignment to a field or an array index is handled like an
   725    // assignment to the struct.
   726    while (true)
   727      {
   728        // Nothing to do for a type that can not be in the heap, or a
   729        // pointer to a type that can not be in the heap.  We check this
   730        // at each level of a struct.
   731        if (!lhs->type()->in_heap())
   732  	return false;
   733        if (lhs->type()->points_to() != NULL
   734  	  && !lhs->type()->points_to()->in_heap())
   735  	return false;
   736  
   737        // For a struct assignment, we don't need a write barrier if all
   738        // the field types can not be in the heap.
   739        Struct_type* st = lhs->type()->struct_type();
   740        if (st != NULL)
   741  	{
   742  	  bool in_heap = false;
   743  	  const Struct_field_list* fields = st->fields();
   744  	  for (Struct_field_list::const_iterator p = fields->begin();
   745  	       p != fields->end();
   746  	       p++)
   747  	    {
   748  	      Type* ft = p->type();
   749  	      if (!ft->has_pointer())
   750  		continue;
   751  	      if (!ft->in_heap())
   752  		continue;
   753  	      if (ft->points_to() != NULL && !ft->points_to()->in_heap())
   754  		continue;
   755  	      in_heap = true;
   756  	      break;
   757  	    }
   758  	  if (!in_heap)
   759  	    return false;
   760  	}
   761  
   762        Field_reference_expression* fre = lhs->field_reference_expression();
   763        if (fre != NULL)
   764  	{
   765  	  lhs = fre->expr();
   766  	  continue;
   767  	}
   768  
   769        Array_index_expression* aie = lhs->array_index_expression();
   770        if (aie != NULL
   771  	  && aie->end() == NULL
   772  	  && !aie->array()->type()->is_slice_type())
   773  	{
   774  	  lhs = aie->array();
   775  	  continue;
   776  	}
   777  
   778        break;
   779      }
   780  
   781    // Nothing to do for an assignment to a temporary.
   782    if (lhs->temporary_reference_expression() != NULL)
   783      return false;
   784  
   785    // Nothing to do for an assignment to a sink.
   786    if (lhs->is_sink_expression())
   787      return false;
   788  
   789    // Nothing to do for an assignment to a local variable that is not
   790    // on the heap.
   791    Var_expression* ve = lhs->var_expression();
   792    if (ve != NULL)
   793      {
   794        Named_object* no = ve->named_object();
   795        if (no->is_variable())
   796  	{
   797  	  Variable* var = no->var_value();
   798  	  if (!var->is_global() && !var->is_in_heap())
   799  	    return false;
   800  	}
   801        else if (no->is_result_variable())
   802  	{
   803  	  Result_variable* rvar = no->result_var_value();
   804  	  if (!rvar->is_in_heap())
   805  	    return false;
   806  	}
   807      }
   808  
   809    // Nothing to do for an assignment to *(convert(&x)) where
   810    // x is local variable or a temporary variable.
   811    Unary_expression* ue = lhs->unary_expression();
   812    if (ue != NULL
   813        && ue->op() == OPERATOR_MULT
   814        && this->is_nonwb_pointer(ue->operand(), nonwb_pointers))
   815      return false;
   816  
   817    // Write barrier needed in other cases.
   818    return true;
   819  }
   820  
   821  // Return whether EXPR is the address of a variable that can be set
   822  // without a write barrier.  That is, if this returns true, then an
   823  // assignment to *EXPR does not require a write barrier.
   824  // NONWB_POINTERS is a set of variables that point to values that do
   825  // not need write barriers.
   826  
   827  bool
   828  Gogo::is_nonwb_pointer(Expression* expr,
   829  		       Unordered_set(const Named_object*)* nonwb_pointers)
   830  {
   831    while (true)
   832      {
   833        if (expr->conversion_expression() != NULL)
   834  	expr = expr->conversion_expression()->expr();
   835        else if (expr->unsafe_conversion_expression() != NULL)
   836  	expr = expr->unsafe_conversion_expression()->expr();
   837        else
   838  	break;
   839      }
   840  
   841    Var_expression* ve = expr->var_expression();
   842    if (ve != NULL
   843        && nonwb_pointers != NULL
   844        && nonwb_pointers->find(ve->named_object()) != nonwb_pointers->end())
   845      return true;
   846  
   847    Unary_expression* ue = expr->unary_expression();
   848    if (ue == NULL || ue->op() != OPERATOR_AND)
   849      return false;
   850    if (this->assign_needs_write_barrier(ue->operand(), nonwb_pointers))
   851      return false;
   852    return true;
   853  }
   854  
   855  // Return a statement that sets LHS to RHS using a write barrier.
   856  // ENCLOSING is the enclosing block.
   857  
   858  Statement*
   859  Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
   860  				Statement_inserter* inserter, Expression* lhs,
   861  				Expression* rhs, Location loc)
   862  {
   863    if (function != NULL && (function->pragmas() & GOPRAGMA_NOWRITEBARRIER) != 0)
   864      go_error_at(loc, "write barrier prohibited");
   865  
   866    Type* type = lhs->type();
   867    go_assert(type->has_pointer());
   868  
   869    Expression* addr;
   870    if (lhs->unary_expression() != NULL
   871        && lhs->unary_expression()->op() == OPERATOR_MULT)
   872      addr = lhs->unary_expression()->operand();
   873    else
   874      {
   875        addr = Expression::make_unary(OPERATOR_AND, lhs, loc);
   876        addr->unary_expression()->set_does_not_escape();
   877      }
   878    Temporary_statement* lhs_temp = Statement::make_temporary(NULL, addr, loc);
   879    inserter->insert(lhs_temp);
   880    lhs = Expression::make_temporary_reference(lhs_temp, loc);
   881  
   882    if (!Type::are_identical(type, rhs->type(),
   883  			   Type::COMPARE_ERRORS | Type::COMPARE_TAGS,
   884  			   NULL)
   885        && rhs->type()->interface_type() != NULL
   886        && !rhs->is_multi_eval_safe())
   887      {
   888        // May need a temporary for interface conversion.
   889        Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc);
   890        inserter->insert(temp);
   891        rhs = Expression::make_temporary_reference(temp, loc);
   892      }
   893    rhs = Expression::convert_for_assignment(this, type, rhs, loc);
   894    Temporary_statement* rhs_temp = NULL;
   895    if (!rhs->is_multi_eval_safe())
   896      {
   897        rhs_temp = Statement::make_temporary(NULL, rhs, loc);
   898        inserter->insert(rhs_temp);
   899        rhs = Expression::make_temporary_reference(rhs_temp, loc);
   900      }
   901  
   902    Expression* indir =
   903        Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc);
   904    Statement* assign = Statement::make_assignment(indir, rhs, loc);
   905  
   906    lhs = Expression::make_temporary_reference(lhs_temp, loc);
   907    if (rhs_temp != NULL)
   908      rhs = Expression::make_temporary_reference(rhs_temp, loc);
   909  
   910    Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type());
   911    lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc);
   912  
   913    Type* uintptr_type = Type::lookup_integer_type("uintptr");
   914    Expression* call;
   915    switch (type->base()->classification())
   916      {
   917      default:
   918        go_unreachable();
   919  
   920      case Type::TYPE_ERROR:
   921        return assign;
   922  
   923      case Type::TYPE_POINTER:
   924      case Type::TYPE_FUNCTION:
   925      case Type::TYPE_MAP:
   926      case Type::TYPE_CHANNEL:
   927        {
   928  	// These types are all represented by a single pointer.
   929  	rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
   930  	call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
   931        }
   932        break;
   933  
   934      case Type::TYPE_STRING:
   935        {
   936          // Assign the length field directly.
   937          Expression* llen =
   938            Expression::make_string_info(indir->copy(),
   939                                         Expression::STRING_INFO_LENGTH,
   940                                         loc);
   941          Expression* rlen =
   942            Expression::make_string_info(rhs,
   943                                         Expression::STRING_INFO_LENGTH,
   944                                         loc);
   945          Statement* as = Statement::make_assignment(llen, rlen, loc);
   946          inserter->insert(as);
   947  
   948          // Assign the data field with a write barrier.
   949          lhs =
   950            Expression::make_string_info(indir->copy(),
   951                                         Expression::STRING_INFO_DATA,
   952                                         loc);
   953          rhs =
   954            Expression::make_string_info(rhs,
   955                                         Expression::STRING_INFO_DATA,
   956                                         loc);
   957          assign = Statement::make_assignment(lhs, rhs, loc);
   958          lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
   959          rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
   960          call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
   961        }
   962        break;
   963  
   964      case Type::TYPE_INTERFACE:
   965        {
   966          // Assign the first field directly.
   967          // The first field is either a type descriptor or a method table.
   968          // Type descriptors are either statically created, or created by
   969          // the reflect package. For the latter the reflect package keeps
   970          // all references.
   971          // Method tables are either statically created or persistently
   972          // allocated.
   973          // In all cases they don't need a write barrier.
   974          Expression* ltab =
   975            Expression::make_interface_info(indir->copy(),
   976                                            Expression::INTERFACE_INFO_METHODS,
   977                                            loc);
   978          Expression* rtab =
   979            Expression::make_interface_info(rhs,
   980                                            Expression::INTERFACE_INFO_METHODS,
   981                                            loc);
   982          Statement* as = Statement::make_assignment(ltab, rtab, loc);
   983          inserter->insert(as);
   984  
   985          // Assign the data field with a write barrier.
   986          lhs =
   987            Expression::make_interface_info(indir->copy(),
   988                                            Expression::INTERFACE_INFO_OBJECT,
   989                                            loc);
   990          rhs =
   991            Expression::make_interface_info(rhs,
   992                                            Expression::INTERFACE_INFO_OBJECT,
   993                                            loc);
   994          assign = Statement::make_assignment(lhs, rhs, loc);
   995          lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
   996          rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
   997          call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
   998        }
   999        break;
  1000  
  1001      case Type::TYPE_ARRAY:
  1002        if (type->is_slice_type())
  1003         {
  1004            // Assign the lenth fields directly.
  1005            Expression* llen =
  1006              Expression::make_slice_info(indir->copy(),
  1007                                          Expression::SLICE_INFO_LENGTH,
  1008                                          loc);
  1009            Expression* rlen =
  1010              Expression::make_slice_info(rhs,
  1011                                          Expression::SLICE_INFO_LENGTH,
  1012                                          loc);
  1013            Statement* as = Statement::make_assignment(llen, rlen, loc);
  1014            inserter->insert(as);
  1015  
  1016            // Assign the capacity fields directly.
  1017            Expression* lcap =
  1018              Expression::make_slice_info(indir->copy(),
  1019                                          Expression::SLICE_INFO_CAPACITY,
  1020                                          loc);
  1021            Expression* rcap =
  1022              Expression::make_slice_info(rhs,
  1023                                          Expression::SLICE_INFO_CAPACITY,
  1024                                          loc);
  1025            as = Statement::make_assignment(lcap, rcap, loc);
  1026            inserter->insert(as);
  1027  
  1028            // Assign the data field with a write barrier.
  1029            lhs =
  1030              Expression::make_slice_info(indir->copy(),
  1031                                          Expression::SLICE_INFO_VALUE_POINTER,
  1032                                          loc);
  1033            rhs =
  1034              Expression::make_slice_info(rhs,
  1035                                          Expression::SLICE_INFO_VALUE_POINTER,
  1036                                          loc);
  1037            assign = Statement::make_assignment(lhs, rhs, loc);
  1038            lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
  1039            rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
  1040            call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
  1041            break;
  1042          }
  1043        // fallthrough
  1044  
  1045      case Type::TYPE_STRUCT:
  1046        if (type->is_direct_iface_type())
  1047          {
  1048            rhs = Expression::unpack_direct_iface(rhs, loc);
  1049            rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
  1050            call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
  1051          }
  1052        else
  1053          {
  1054            // TODO: split assignments for small struct/array?
  1055            rhs = Expression::make_unary(OPERATOR_AND, rhs, loc);
  1056            rhs->unary_expression()->set_does_not_escape();
  1057            call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3,
  1058                                      Expression::make_type_descriptor(type, loc),
  1059                                      lhs, rhs);
  1060          }
  1061        break;
  1062      }
  1063  
  1064    return this->check_write_barrier(enclosing, assign,
  1065  				   Statement::make_statement(call, false));
  1066  }
  1067  
  1068  // Return a statement that tests whether write barriers are enabled
  1069  // and executes either the efficient code or the write barrier
  1070  // function call, depending.
  1071  
  1072  Statement*
  1073  Gogo::check_write_barrier(Block* enclosing, Statement* without,
  1074  			  Statement* with)
  1075  {
  1076    Location loc = without->location();
  1077    Named_object* wb = this->write_barrier_variable();
  1078    // We pretend that writeBarrier is a uint32, so that we do a
  1079    // 32-bit load.  That is what the gc toolchain does.
  1080    Type* void_type = Type::make_void_type();
  1081    Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
  1082    Type* uint32_type = Type::lookup_integer_type("uint32");
  1083    Type* puint32_type = Type::make_pointer_type(uint32_type);
  1084    Expression* ref = Expression::make_var_reference(wb, loc);
  1085    ref = Expression::make_unary(OPERATOR_AND, ref, loc);
  1086    ref = Expression::make_cast(unsafe_pointer_type, ref, loc);
  1087    ref = Expression::make_cast(puint32_type, ref, loc);
  1088    ref = Expression::make_dereference(ref,
  1089                                       Expression::NIL_CHECK_NOT_NEEDED, loc);
  1090    Expression* zero = Expression::make_integer_ul(0, ref->type(), loc);
  1091    Expression* cond = Expression::make_binary(OPERATOR_EQEQ, ref, zero, loc);
  1092  
  1093    Block* then_block = new Block(enclosing, loc);
  1094    then_block->add_statement(without);
  1095  
  1096    Block* else_block = new Block(enclosing, loc);
  1097    else_block->add_statement(with);
  1098  
  1099    return Statement::make_if_statement(cond, then_block, else_block, loc);
  1100  }