Fix possible wrong-code with masked store-lanes
[official-gcc.git] / gcc / go / gofrontend / wb.cc
blobd0d6326e0de3372d2595eae5b770b6190c992b66
1 // wb.cc -- Add write barriers as needed.
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.
7 #include "go-system.h"
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"
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.
24 class Mark_address_taken : public Traverse
26 public:
27 Mark_address_taken(Gogo* gogo)
28 : Traverse(traverse_functions
29 | traverse_statements
30 | traverse_expressions),
31 gogo_(gogo), function_(NULL)
32 { }
34 int
35 function(Named_object*);
37 int
38 statement(Block*, size_t*, Statement*);
40 int
41 expression(Expression**);
43 private:
44 // General IR.
45 Gogo* gogo_;
46 // The function we are traversing.
47 Named_object* function_;
50 // Record a function.
52 int
53 Mark_address_taken::function(Named_object* no)
55 go_assert(this->function_ == NULL);
56 this->function_ = no;
57 int t = no->func_value()->traverse(this);
58 this->function_ = NULL;
60 if (t == TRAVERSE_EXIT)
61 return t;
62 return TRAVERSE_SKIP_COMPONENTS;
65 // Traverse a statement.
67 int
68 Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s)
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())
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()))
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);
97 return TRAVERSE_CONTINUE;
100 // Mark variable addresses taken.
103 Mark_address_taken::expression(Expression** pexpr)
105 Expression* expr = *pexpr;
106 Unary_expression* ue = expr->unary_expression();
107 if (ue != NULL)
108 ue->check_operand_address_taken(this->gogo_);
110 Array_index_expression* aie = expr->array_index_expression();
111 if (aie != NULL
112 && aie->end() != NULL
113 && !aie->array()->type()->is_slice_type())
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);
125 if (expr->allocation_expression() != NULL)
127 Node* n = Node::make_node(expr);
128 if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
129 expr->allocation_expression()->set_allocate_on_stack();
131 if (expr->heap_expression() != NULL)
133 Node* n = Node::make_node(expr);
134 if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
135 expr->heap_expression()->set_allocate_on_stack();
137 if (expr->slice_literal() != NULL)
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();
144 // Rewrite non-escaping makeslice with constant size to stack allocation.
145 Slice_value_expression* sve = expr->slice_value_expression();
146 if (sve != NULL)
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)
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)
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));
186 return TRAVERSE_CONTINUE;
189 // Check variables and closures do not escape when compiling runtime.
191 class Check_escape : public Traverse
193 public:
194 Check_escape()
195 : Traverse(traverse_expressions | traverse_variables)
199 expression(Expression**);
202 variable(Named_object*);
206 Check_escape::variable(Named_object* no)
208 if ((no->is_variable() && no->var_value()->is_in_heap())
209 || (no->is_result_variable()
210 && no->result_var_value()->is_in_heap()))
211 go_error_at(no->location(),
212 "%s escapes to heap, not allowed in runtime",
213 no->message_name().c_str());
214 return TRAVERSE_CONTINUE;
218 Check_escape::expression(Expression** pexpr)
220 Expression* expr = *pexpr;
221 Func_expression* fe = expr->func_expression();
222 if (fe != NULL && fe->closure() != NULL)
224 Node* n = Node::make_node(expr);
225 if (n->encoding() == Node::ESCAPE_HEAP)
226 go_error_at(expr->location(),
227 "heap-allocated closure, not allowed in runtime");
229 return TRAVERSE_CONTINUE;
232 // Collect all writebarrierrec functions. This is used when compiling
233 // the runtime package, to propagate //go:nowritebarrierrec.
235 class Collect_writebarrierrec_functions : public Traverse
237 public:
238 Collect_writebarrierrec_functions(std::vector<Named_object*>* worklist)
239 : Traverse(traverse_functions),
240 worklist_(worklist)
243 private:
245 function(Named_object*);
247 // The collected functions are put here.
248 std::vector<Named_object*>* worklist_;
252 Collect_writebarrierrec_functions::function(Named_object* no)
254 if (no->is_function()
255 && no->func_value()->enclosing() == NULL
256 && (no->func_value()->pragmas() & GOPRAGMA_NOWRITEBARRIERREC) != 0)
258 go_assert((no->func_value()->pragmas() & GOPRAGMA_MARK) == 0);
259 this->worklist_->push_back(no);
261 return TRAVERSE_CONTINUE;
264 // Collect all callees of this function. We only care about locally
265 // defined, known, functions.
267 class Collect_callees : public Traverse
269 public:
270 Collect_callees(std::vector<Named_object*>* worklist)
271 : Traverse(traverse_expressions),
272 worklist_(worklist)
275 private:
277 expression(Expression**);
279 // The collected callees are put here.
280 std::vector<Named_object*>* worklist_;
284 Collect_callees::expression(Expression** pexpr)
286 Call_expression* ce = (*pexpr)->call_expression();
287 if (ce != NULL)
289 Func_expression* fe = ce->fn()->func_expression();
290 if (fe != NULL)
292 Named_object* no = fe->named_object();
293 if (no->package() == NULL && no->is_function())
295 // The function runtime.systemstack is special, in that
296 // it is a common way to call a function in the runtime:
297 // mark its argument if we can.
298 if (Gogo::unpack_hidden_name(no->name()) != "systemstack")
299 this->worklist_->push_back(no);
300 else if (ce->args()->size() > 0)
302 fe = ce->args()->front()->func_expression();
303 if (fe != NULL)
305 no = fe->named_object();
306 if (no->package() == NULL && no->is_function())
307 this->worklist_->push_back(no);
313 return TRAVERSE_CONTINUE;
316 // When compiling the runtime package, propagate //go:nowritebarrierrec
317 // annotations. A function marked as //go:nowritebarrierrec does not
318 // permit write barriers, and also all the functions that it calls,
319 // recursively, do not permit write barriers. Except that a
320 // //go:yeswritebarrierrec annotation permits write barriers even if
321 // called by a //go:nowritebarrierrec function. Here we turn
322 // //go:nowritebarrierrec into //go:nowritebarrier, as appropriate.
324 void
325 Gogo::propagate_writebarrierrec()
327 std::vector<Named_object*> worklist;
328 Collect_writebarrierrec_functions cwf(&worklist);
329 this->traverse(&cwf);
331 Collect_callees cc(&worklist);
333 while (!worklist.empty())
335 Named_object* no = worklist.back();
336 worklist.pop_back();
338 unsigned int pragmas = no->func_value()->pragmas();
339 if ((pragmas & GOPRAGMA_MARK) != 0)
341 // We've already seen this function.
342 continue;
344 if ((pragmas & GOPRAGMA_YESWRITEBARRIERREC) != 0)
346 // We don't want to propagate //go:nowritebarrierrec into
347 // this function or it's callees.
348 continue;
351 no->func_value()->set_pragmas(pragmas
352 | GOPRAGMA_NOWRITEBARRIER
353 | GOPRAGMA_MARK);
355 no->func_value()->traverse(&cc);
359 // Add write barriers to the IR. This are required by the concurrent
360 // garbage collector. A write barrier is needed for any write of a
361 // pointer into memory controlled by the garbage collector. Write
362 // barriers are not required for writes to local variables that live
363 // on the stack. Write barriers are only required when the runtime
364 // enables them, which can be checked using a run time check on
365 // runtime.writeBarrier.enabled.
367 // Essentially, for each assignment A = B, where A is or contains a
368 // pointer, and where A is not, or at any rate may not be, a stack
369 // variable, we rewrite it into
370 // if runtime.writeBarrier.enabled {
371 // typedmemmove(typeof(A), &A, &B)
372 // } else {
373 // A = B
374 // }
376 // The test of runtime.writeBarrier.Enabled is implemented by treating
377 // the variable as a *uint32, and testing *runtime.writeBarrier != 0.
378 // This is compatible with the definition in the runtime package.
380 // For types that are pointer shared (pointers, maps, chans, funcs),
381 // we replaced the call to typedmemmove with gcWriteBarrier(&A, B).
382 // As far as the GC is concerned, all pointers are the same, so it
383 // doesn't need the type descriptor.
385 // There are possible optimizations that are not implemented.
387 // runtime.writeBarrier can only change when the goroutine is
388 // preempted, which in practice means when a call is made into the
389 // runtime package, so we could optimize by only testing it once
390 // between function calls.
392 // A slice could be handled with a call to gcWriteBarrier plus two
393 // integer moves.
395 // Traverse the IR adding write barriers.
397 class Write_barriers : public Traverse
399 public:
400 Write_barriers(Gogo* gogo)
401 : Traverse(traverse_functions
402 | traverse_blocks
403 | traverse_variables
404 | traverse_statements),
405 gogo_(gogo), function_(NULL), statements_added_(),
406 nonwb_pointers_()
410 function(Named_object*);
413 block(Block*);
416 variable(Named_object*);
419 statement(Block*, size_t* pindex, Statement*);
421 private:
422 // General IR.
423 Gogo* gogo_;
424 // Current function.
425 Function* function_;
426 // Statements introduced.
427 Statement_inserter::Statements statements_added_;
428 // Within a single block, pointer variables that point to values
429 // that do not need write barriers.
430 Unordered_set(const Named_object*) nonwb_pointers_;
433 // Traverse a function. Just record it for later.
436 Write_barriers::function(Named_object* no)
438 go_assert(this->function_ == NULL);
439 this->function_ = no->func_value();
440 int t = this->function_->traverse(this);
441 this->function_ = NULL;
443 if (t == TRAVERSE_EXIT)
444 return t;
445 return TRAVERSE_SKIP_COMPONENTS;
448 // Traverse a block. Clear anything we know about local pointer
449 // variables.
452 Write_barriers::block(Block*)
454 this->nonwb_pointers_.clear();
455 return TRAVERSE_CONTINUE;
458 // Insert write barriers for a global variable: ensure that variable
459 // initialization is handled correctly. This is rarely needed, since
460 // we currently don't enable background GC until after all global
461 // variables are initialized. But we do need this if an init function
462 // calls runtime.GC.
465 Write_barriers::variable(Named_object* no)
467 // We handle local variables in the variable declaration statement.
468 // We only have to handle global variables here.
469 if (!no->is_variable())
470 return TRAVERSE_CONTINUE;
471 Variable* var = no->var_value();
472 if (!var->is_global())
473 return TRAVERSE_CONTINUE;
475 // Nothing to do if there is no initializer.
476 Expression* init = var->init();
477 if (init == NULL)
478 return TRAVERSE_CONTINUE;
480 // Nothing to do for variables that do not contain any pointers.
481 if (!var->type()->has_pointer())
482 return TRAVERSE_CONTINUE;
484 // Nothing to do if the initializer is static.
485 init = Expression::make_cast(var->type(), init, var->location());
486 if (!var->has_pre_init() && init->is_static_initializer())
487 return TRAVERSE_CONTINUE;
489 // Nothing to do for a type that can not be in the heap, or a
490 // pointer to a type that can not be in the heap.
491 if (!var->type()->in_heap())
492 return TRAVERSE_CONTINUE;
493 if (var->type()->points_to() != NULL && !var->type()->points_to()->in_heap())
494 return TRAVERSE_CONTINUE;
496 // Otherwise change the initializer into a pre_init assignment
497 // statement with a write barrier.
499 // We can't check for a dependency of the variable on itself after
500 // we make this change, because the preinit statement will always
501 // depend on the variable (since it assigns to it). So check for a
502 // self-dependency now.
503 this->gogo_->check_self_dep(no);
505 // Replace the initializer.
506 Location loc = init->location();
507 Expression* ref = Expression::make_var_reference(no, loc);
509 Statement_inserter inserter(this->gogo_, var, &this->statements_added_);
510 Statement* s = this->gogo_->assign_with_write_barrier(NULL, NULL, &inserter,
511 ref, init, loc);
512 this->statements_added_.insert(s);
514 var->add_preinit_statement(this->gogo_, s);
515 var->clear_init();
517 return TRAVERSE_CONTINUE;
520 // Insert write barriers for statements.
523 Write_barriers::statement(Block* block, size_t* pindex, Statement* s)
525 if (this->statements_added_.find(s) != this->statements_added_.end())
526 return TRAVERSE_SKIP_COMPONENTS;
528 switch (s->classification())
530 default:
531 break;
533 case Statement::STATEMENT_VARIABLE_DECLARATION:
535 Variable_declaration_statement* vds =
536 s->variable_declaration_statement();
537 Named_object* no = vds->var();
538 Variable* var = no->var_value();
540 // We may need to emit a write barrier for the initialization
541 // of the variable.
543 // Nothing to do for a variable with no initializer.
544 Expression* init = var->init();
545 if (init == NULL)
546 break;
548 // Nothing to do if the variable is not in the heap. Only
549 // local variables get declaration statements, and local
550 // variables on the stack do not require write barriers.
551 if (!var->is_in_heap())
553 // If this is a pointer variable, and assigning through
554 // the initializer does not require a write barrier,
555 // record that fact.
556 if (var->type()->points_to() != NULL
557 && this->gogo_->is_nonwb_pointer(init, &this->nonwb_pointers_))
558 this->nonwb_pointers_.insert(no);
560 break;
563 // Nothing to do if the variable does not contain any pointers.
564 if (!var->type()->has_pointer())
565 break;
567 // Nothing to do for a type that can not be in the heap, or a
568 // pointer to a type that can not be in the heap.
569 if (!var->type()->in_heap())
570 break;
571 if (var->type()->points_to() != NULL
572 && !var->type()->points_to()->in_heap())
573 break;
575 // Otherwise initialize the variable with a write barrier.
577 Function* function = this->function_;
578 Location loc = init->location();
579 Statement_inserter inserter(block, pindex, &this->statements_added_);
581 // Insert the variable declaration statement with no
582 // initializer, so that the variable exists.
583 var->clear_init();
584 inserter.insert(s);
586 // Create a statement that initializes the variable with a
587 // write barrier.
588 Expression* ref = Expression::make_var_reference(no, loc);
589 Statement* assign = this->gogo_->assign_with_write_barrier(function,
590 block,
591 &inserter,
592 ref, init,
593 loc);
594 this->statements_added_.insert(assign);
596 // Replace the old variable declaration statement with the new
597 // initialization.
598 block->replace_statement(*pindex, assign);
600 break;
602 case Statement::STATEMENT_ASSIGNMENT:
604 Assignment_statement* as = s->assignment_statement();
606 Expression* lhs = as->lhs();
607 Expression* rhs = as->rhs();
609 // Keep track of variables whose values do not escape.
610 Var_expression* lhsve = lhs->var_expression();
611 if (lhsve != NULL && lhsve->type()->points_to() != NULL)
613 Named_object* no = lhsve->named_object();
614 if (this->gogo_->is_nonwb_pointer(rhs, &this->nonwb_pointers_))
615 this->nonwb_pointers_.insert(no);
616 else
617 this->nonwb_pointers_.erase(no);
620 if (as->omit_write_barrier())
621 break;
623 // We may need to emit a write barrier for the assignment.
625 if (!this->gogo_->assign_needs_write_barrier(lhs,
626 &this->nonwb_pointers_))
627 break;
629 // Change the assignment to use a write barrier.
630 Function* function = this->function_;
631 Location loc = as->location();
632 Statement_inserter inserter =
633 Statement_inserter(block, pindex, &this->statements_added_);
634 Statement* assign = this->gogo_->assign_with_write_barrier(function,
635 block,
636 &inserter,
637 lhs, rhs,
638 loc);
639 this->statements_added_.insert(assign);
640 block->replace_statement(*pindex, assign);
642 break;
645 return TRAVERSE_CONTINUE;
648 // The write barrier pass.
650 void
651 Gogo::add_write_barriers()
653 if (saw_errors())
654 return;
656 Mark_address_taken mat(this);
657 this->traverse(&mat);
659 if (this->compiling_runtime() && this->package_name() == "runtime")
661 this->propagate_writebarrierrec();
663 Check_escape chk;
664 this->traverse(&chk);
667 Write_barriers wb(this);
668 this->traverse(&wb);
671 // Return the runtime.writeBarrier variable.
673 Named_object*
674 Gogo::write_barrier_variable()
676 static Named_object* write_barrier_var;
677 if (write_barrier_var == NULL)
679 Location bloc = Linemap::predeclared_location();
681 Type* bool_type = Type::lookup_bool_type();
682 Array_type* pad_type =
683 Type::make_array_type(Type::lookup_integer_type("byte"),
684 Expression::make_integer_ul(3, NULL, bloc));
685 Type* uint64_type = Type::lookup_integer_type("uint64");
686 Type* wb_type = Type::make_builtin_struct_type(5,
687 "enabled", bool_type,
688 "pad", pad_type,
689 "needed", bool_type,
690 "cgo", bool_type,
691 "alignme", uint64_type);
693 Variable* var = new Variable(wb_type, NULL,
694 true, false, false, bloc);
696 bool add_to_globals;
697 Package* package = this->add_imported_package("runtime", "_", false,
698 "runtime", "runtime",
699 bloc, &add_to_globals);
700 write_barrier_var = Named_object::make_variable("writeBarrier",
701 package, var);
704 return write_barrier_var;
707 // Return whether an assignment that sets LHS needs a write barrier.
708 // NONWB_POINTERS is a set of variables that point to values that do
709 // not need write barriers.
711 bool
712 Gogo::assign_needs_write_barrier(
713 Expression* lhs,
714 Unordered_set(const Named_object*)* nonwb_pointers)
716 // Nothing to do if the variable does not contain any pointers.
717 if (!lhs->type()->has_pointer())
718 return false;
720 // An assignment to a field or an array index is handled like an
721 // assignment to the struct.
722 while (true)
724 // Nothing to do for a type that can not be in the heap, or a
725 // pointer to a type that can not be in the heap. We check this
726 // at each level of a struct.
727 if (!lhs->type()->in_heap())
728 return false;
729 if (lhs->type()->points_to() != NULL
730 && !lhs->type()->points_to()->in_heap())
731 return false;
733 // For a struct assignment, we don't need a write barrier if all
734 // the field types can not be in the heap.
735 Struct_type* st = lhs->type()->struct_type();
736 if (st != NULL)
738 bool in_heap = false;
739 const Struct_field_list* fields = st->fields();
740 for (Struct_field_list::const_iterator p = fields->begin();
741 p != fields->end();
742 p++)
744 Type* ft = p->type();
745 if (!ft->has_pointer())
746 continue;
747 if (!ft->in_heap())
748 continue;
749 if (ft->points_to() != NULL && !ft->points_to()->in_heap())
750 continue;
751 in_heap = true;
752 break;
754 if (!in_heap)
755 return false;
758 Field_reference_expression* fre = lhs->field_reference_expression();
759 if (fre != NULL)
761 lhs = fre->expr();
762 continue;
765 Array_index_expression* aie = lhs->array_index_expression();
766 if (aie != NULL
767 && aie->end() == NULL
768 && !aie->array()->type()->is_slice_type())
770 lhs = aie->array();
771 continue;
774 break;
777 // Nothing to do for an assignment to a temporary.
778 if (lhs->temporary_reference_expression() != NULL)
779 return false;
781 // Nothing to do for an assignment to a sink.
782 if (lhs->is_sink_expression())
783 return false;
785 // Nothing to do for an assignment to a local variable that is not
786 // on the heap.
787 Var_expression* ve = lhs->var_expression();
788 if (ve != NULL)
790 Named_object* no = ve->named_object();
791 if (no->is_variable())
793 Variable* var = no->var_value();
794 if (!var->is_global() && !var->is_in_heap())
795 return false;
797 else if (no->is_result_variable())
799 Result_variable* rvar = no->result_var_value();
800 if (!rvar->is_in_heap())
801 return false;
805 // Nothing to do for an assignment to *(convert(&x)) where
806 // x is local variable or a temporary variable.
807 Unary_expression* ue = lhs->unary_expression();
808 if (ue != NULL
809 && ue->op() == OPERATOR_MULT
810 && this->is_nonwb_pointer(ue->operand(), nonwb_pointers))
811 return false;
813 // Write barrier needed in other cases.
814 return true;
817 // Return whether EXPR is the address of a variable that can be set
818 // without a write barrier. That is, if this returns true, then an
819 // assignment to *EXPR does not require a write barrier.
820 // NONWB_POINTERS is a set of variables that point to values that do
821 // not need write barriers.
823 bool
824 Gogo::is_nonwb_pointer(Expression* expr,
825 Unordered_set(const Named_object*)* nonwb_pointers)
827 while (true)
829 if (expr->conversion_expression() != NULL)
830 expr = expr->conversion_expression()->expr();
831 else if (expr->unsafe_conversion_expression() != NULL)
832 expr = expr->unsafe_conversion_expression()->expr();
833 else
834 break;
837 Var_expression* ve = expr->var_expression();
838 if (ve != NULL
839 && nonwb_pointers != NULL
840 && nonwb_pointers->find(ve->named_object()) != nonwb_pointers->end())
841 return true;
843 Unary_expression* ue = expr->unary_expression();
844 if (ue == NULL || ue->op() != OPERATOR_AND)
845 return false;
846 if (this->assign_needs_write_barrier(ue->operand(), nonwb_pointers))
847 return false;
848 return true;
851 // Return a statement that sets LHS to RHS using a write barrier.
852 // ENCLOSING is the enclosing block.
854 Statement*
855 Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
856 Statement_inserter* inserter, Expression* lhs,
857 Expression* rhs, Location loc)
859 if (function != NULL && (function->pragmas() & GOPRAGMA_NOWRITEBARRIER) != 0)
860 go_error_at(loc, "write barrier prohibited");
862 Type* type = lhs->type();
863 go_assert(type->has_pointer());
865 Expression* addr;
866 if (lhs->unary_expression() != NULL
867 && lhs->unary_expression()->op() == OPERATOR_MULT)
868 addr = lhs->unary_expression()->operand();
869 else
871 addr = Expression::make_unary(OPERATOR_AND, lhs, loc);
872 addr->unary_expression()->set_does_not_escape();
874 Temporary_statement* lhs_temp = Statement::make_temporary(NULL, addr, loc);
875 lhs_temp->determine_types(this);
876 inserter->insert(lhs_temp);
877 lhs = Expression::make_temporary_reference(lhs_temp, loc);
879 if (!Type::are_identical(type, rhs->type(),
880 Type::COMPARE_ERRORS | Type::COMPARE_TAGS,
881 NULL)
882 && rhs->type()->interface_type() != NULL
883 && !rhs->is_multi_eval_safe())
885 // May need a temporary for interface conversion.
886 Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc);
887 temp->determine_types(this);
888 inserter->insert(temp);
889 rhs = Expression::make_temporary_reference(temp, loc);
891 rhs = Expression::convert_for_assignment(this, type, rhs, loc);
892 Temporary_statement* rhs_temp = NULL;
893 if (!rhs->is_multi_eval_safe())
895 rhs_temp = Statement::make_temporary(NULL, rhs, loc);
896 rhs_temp->determine_types(this);
897 inserter->insert(rhs_temp);
898 rhs = Expression::make_temporary_reference(rhs_temp, loc);
901 Expression* indir =
902 Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc);
903 Statement* assign = Statement::make_assignment(indir, rhs, loc);
905 lhs = Expression::make_temporary_reference(lhs_temp, loc);
906 if (rhs_temp != NULL)
907 rhs = Expression::make_temporary_reference(rhs_temp, loc);
909 Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type());
910 lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc);
912 Type* uintptr_type = Type::lookup_integer_type("uintptr");
913 Expression* call;
914 switch (type->base()->classification())
916 default:
917 go_unreachable();
919 case Type::TYPE_ERROR:
920 return assign;
922 case Type::TYPE_POINTER:
923 case Type::TYPE_FUNCTION:
924 case Type::TYPE_MAP:
925 case Type::TYPE_CHANNEL:
927 // These types are all represented by a single pointer.
928 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
929 call = Runtime::make_call(this, Runtime::GCWRITEBARRIER, loc, 2,
930 lhs, rhs);
932 break;
934 case Type::TYPE_STRING:
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 as->determine_types(this);
947 inserter->insert(as);
949 // Assign the data field with a write barrier.
950 lhs =
951 Expression::make_string_info(indir->copy(),
952 Expression::STRING_INFO_DATA,
953 loc);
954 rhs =
955 Expression::make_string_info(rhs,
956 Expression::STRING_INFO_DATA,
957 loc);
958 assign = Statement::make_assignment(lhs, rhs, loc);
959 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
960 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
961 call = Runtime::make_call(this, Runtime::GCWRITEBARRIER, loc, 2,
962 lhs, rhs);
964 break;
966 case Type::TYPE_INTERFACE:
968 // Assign the first field directly.
969 // The first field is either a type descriptor or a method table.
970 // Type descriptors are either statically created, or created by
971 // the reflect package. For the latter the reflect package keeps
972 // all references.
973 // Method tables are either statically created or persistently
974 // allocated.
975 // In all cases they don't need a write barrier.
976 Expression* ltab =
977 Expression::make_interface_info(indir->copy(),
978 Expression::INTERFACE_INFO_METHODS,
979 loc);
980 Expression* rtab =
981 Expression::make_interface_info(rhs,
982 Expression::INTERFACE_INFO_METHODS,
983 loc);
984 Statement* as = Statement::make_assignment(ltab, rtab, loc);
985 as->determine_types(this);
986 inserter->insert(as);
988 // Assign the data field with a write barrier.
989 lhs =
990 Expression::make_interface_info(indir->copy(),
991 Expression::INTERFACE_INFO_OBJECT,
992 loc);
993 rhs =
994 Expression::make_interface_info(rhs,
995 Expression::INTERFACE_INFO_OBJECT,
996 loc);
997 assign = Statement::make_assignment(lhs, rhs, loc);
998 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
999 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
1000 call = Runtime::make_call(this, Runtime::GCWRITEBARRIER, loc, 2,
1001 lhs, rhs);
1003 break;
1005 case Type::TYPE_ARRAY:
1006 if (type->is_slice_type())
1008 // Assign the lenth fields directly.
1009 Expression* llen =
1010 Expression::make_slice_info(indir->copy(),
1011 Expression::SLICE_INFO_LENGTH,
1012 loc);
1013 Expression* rlen =
1014 Expression::make_slice_info(rhs,
1015 Expression::SLICE_INFO_LENGTH,
1016 loc);
1017 Statement* as = Statement::make_assignment(llen, rlen, loc);
1018 as->determine_types(this);
1019 inserter->insert(as);
1021 // Assign the capacity fields directly.
1022 Expression* lcap =
1023 Expression::make_slice_info(indir->copy(),
1024 Expression::SLICE_INFO_CAPACITY,
1025 loc);
1026 Expression* rcap =
1027 Expression::make_slice_info(rhs,
1028 Expression::SLICE_INFO_CAPACITY,
1029 loc);
1030 as = Statement::make_assignment(lcap, rcap, loc);
1031 as->determine_types(this);
1032 inserter->insert(as);
1034 // Assign the data field with a write barrier.
1035 lhs =
1036 Expression::make_slice_info(indir->copy(),
1037 Expression::SLICE_INFO_VALUE_POINTER,
1038 loc);
1039 rhs =
1040 Expression::make_slice_info(rhs,
1041 Expression::SLICE_INFO_VALUE_POINTER,
1042 loc);
1043 assign = Statement::make_assignment(lhs, rhs, loc);
1044 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
1045 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
1046 call = Runtime::make_call(this, Runtime::GCWRITEBARRIER, loc, 2,
1047 lhs, rhs);
1048 break;
1050 // fallthrough
1052 case Type::TYPE_STRUCT:
1053 if (type->is_direct_iface_type())
1055 rhs = Expression::unpack_direct_iface(rhs, loc);
1056 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
1057 call = Runtime::make_call(this, Runtime::GCWRITEBARRIER, loc, 2,
1058 lhs, rhs);
1060 else
1062 // TODO: split assignments for small struct/array?
1063 rhs = Expression::make_unary(OPERATOR_AND, rhs, loc);
1064 rhs->unary_expression()->set_does_not_escape();
1065 call = Runtime::make_call(this, Runtime::TYPEDMEMMOVE, loc, 3,
1066 Expression::make_type_descriptor(type, loc),
1067 lhs, rhs);
1069 break;
1072 return this->check_write_barrier(enclosing, assign,
1073 Statement::make_statement(call, false));
1076 // Return a statement that tests whether write barriers are enabled
1077 // and executes either the efficient code or the write barrier
1078 // function call, depending.
1080 Statement*
1081 Gogo::check_write_barrier(Block* enclosing, Statement* without,
1082 Statement* with)
1084 Location loc = without->location();
1085 Named_object* wb = this->write_barrier_variable();
1086 // We pretend that writeBarrier is a uint32, so that we do a
1087 // 32-bit load. That is what the gc toolchain does.
1088 Type* void_type = Type::make_void_type();
1089 Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
1090 Type* uint32_type = Type::lookup_integer_type("uint32");
1091 Type* puint32_type = Type::make_pointer_type(uint32_type);
1092 Expression* ref = Expression::make_var_reference(wb, loc);
1093 ref = Expression::make_unary(OPERATOR_AND, ref, loc);
1094 ref = Expression::make_cast(unsafe_pointer_type, ref, loc);
1095 ref = Expression::make_cast(puint32_type, ref, loc);
1096 ref = Expression::make_dereference(ref,
1097 Expression::NIL_CHECK_NOT_NEEDED, loc);
1098 Expression* zero = Expression::make_integer_ul(0, ref->type(), loc);
1099 Expression* cond = Expression::make_binary(OPERATOR_EQEQ, ref, zero, loc);
1101 Block* then_block = new Block(enclosing, loc);
1102 then_block->add_statement(without);
1104 Block* else_block = new Block(enclosing, loc);
1105 else_block->add_statement(with);
1107 Statement* s = Statement::make_if_statement(cond, then_block, else_block,
1108 loc);
1109 s->determine_types(this);
1110 return s;