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.
10 #include "go-diagnostics.h"
14 #include "expressions.h"
15 #include "statements.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
27 Mark_address_taken(Gogo
* gogo
)
28 : Traverse(traverse_functions
30 | traverse_expressions
),
31 gogo_(gogo
), function_(NULL
)
35 function(Named_object
*);
38 statement(Block
*, size_t*, Statement
*);
41 expression(Expression
**);
46 // The function we are traversing.
47 Named_object
* function_
;
53 Mark_address_taken::function(Named_object
* no
)
55 go_assert(this->function_
== NULL
);
57 int t
= no
->func_value()->traverse(this);
58 this->function_
= NULL
;
60 if (t
== TRAVERSE_EXIT
)
62 return TRAVERSE_SKIP_COMPONENTS
;
65 // Traverse a statement.
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();
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
);
85 rce
->builtin_call_expression()->flatten_append(this->gogo_
,
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();
108 ue
->check_operand_address_taken(this->gogo_
);
110 Array_index_expression
* aie
= expr
->array_index_expression();
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
)
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();
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
;
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
;
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
,
178 Expression::make_slice_value(expr
->type(), ptr
, len_arg
,
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
194 Check_escape(Gogo
* gogo
)
195 : Traverse(traverse_expressions
| traverse_variables
),
200 expression(Expression
**);
203 variable(Named_object
*);
210 Check_escape::variable(Named_object
* no
)
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
;
222 Check_escape::expression(Expression
** pexpr
)
224 Expression
* expr
= *pexpr
;
225 Func_expression
* fe
= expr
->func_expression();
226 if (fe
!= NULL
&& fe
->closure() != NULL
)
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");
233 return TRAVERSE_CONTINUE
;
236 // Collect all writebarrierrec functions. This is used when compiling
237 // the runtime package, to propagate //go:nowritebarrierrec.
239 class Collect_writebarrierrec_functions
: public Traverse
242 Collect_writebarrierrec_functions(std::vector
<Named_object
*>* worklist
)
243 : Traverse(traverse_functions
),
249 function(Named_object
*);
251 // The collected functions are put here.
252 std::vector
<Named_object
*>* worklist_
;
256 Collect_writebarrierrec_functions::function(Named_object
* no
)
258 if (no
->is_function()
259 && no
->func_value()->enclosing() == NULL
260 && (no
->func_value()->pragmas() & GOPRAGMA_NOWRITEBARRIERREC
) != 0)
262 go_assert((no
->func_value()->pragmas() & GOPRAGMA_MARK
) == 0);
263 this->worklist_
->push_back(no
);
265 return TRAVERSE_CONTINUE
;
268 // Collect all callees of this function. We only care about locally
269 // defined, known, functions.
271 class Collect_callees
: public Traverse
274 Collect_callees(std::vector
<Named_object
*>* worklist
)
275 : Traverse(traverse_expressions
),
281 expression(Expression
**);
283 // The collected callees are put here.
284 std::vector
<Named_object
*>* worklist_
;
288 Collect_callees::expression(Expression
** pexpr
)
290 Call_expression
* ce
= (*pexpr
)->call_expression();
293 Func_expression
* fe
= ce
->fn()->func_expression();
296 Named_object
* no
= fe
->named_object();
297 if (no
->package() == NULL
&& no
->is_function())
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)
306 fe
= ce
->args()->front()->func_expression();
309 no
= fe
->named_object();
310 if (no
->package() == NULL
&& no
->is_function())
311 this->worklist_
->push_back(no
);
317 return TRAVERSE_CONTINUE
;
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.
329 Gogo::propagate_writebarrierrec()
331 std::vector
<Named_object
*> worklist
;
332 Collect_writebarrierrec_functions
cwf(&worklist
);
333 this->traverse(&cwf
);
335 Collect_callees
cc(&worklist
);
337 while (!worklist
.empty())
339 Named_object
* no
= worklist
.back();
342 unsigned int pragmas
= no
->func_value()->pragmas();
343 if ((pragmas
& GOPRAGMA_MARK
) != 0)
345 // We've already seen this function.
348 if ((pragmas
& GOPRAGMA_YESWRITEBARRIERREC
) != 0)
350 // We don't want to propagate //go:nowritebarrierrec into
351 // this function or it's callees.
355 no
->func_value()->set_pragmas(pragmas
356 | GOPRAGMA_NOWRITEBARRIER
359 no
->func_value()->traverse(&cc
);
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.
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)
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.
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.
389 // There are possible optimizations that are not implemented.
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.
396 // A slice could be handled with a call to gcWriteBarrier plus two
399 // Traverse the IR adding write barriers.
401 class Write_barriers
: public Traverse
404 Write_barriers(Gogo
* gogo
)
405 : Traverse(traverse_functions
408 | traverse_statements
),
409 gogo_(gogo
), function_(NULL
), statements_added_(),
414 function(Named_object
*);
420 variable(Named_object
*);
423 statement(Block
*, size_t* pindex
, Statement
*);
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_
;
437 // Traverse a function. Just record it for later.
440 Write_barriers::function(Named_object
* no
)
442 go_assert(this->function_
== NULL
);
443 this->function_
= no
->func_value();
444 int t
= this->function_
->traverse(this);
445 this->function_
= NULL
;
447 if (t
== TRAVERSE_EXIT
)
449 return TRAVERSE_SKIP_COMPONENTS
;
452 // Traverse a block. Clear anything we know about local pointer
456 Write_barriers::block(Block
*)
458 this->nonwb_pointers_
.clear();
459 return TRAVERSE_CONTINUE
;
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
469 Write_barriers::variable(Named_object
* no
)
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
;
479 // Nothing to do if there is no initializer.
480 Expression
* init
= var
->init();
482 return TRAVERSE_CONTINUE
;
484 // Nothing to do for variables that do not contain any pointers.
485 if (!var
->type()->has_pointer())
486 return TRAVERSE_CONTINUE
;
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
;
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
;
500 // Otherwise change the initializer into a pre_init assignment
501 // statement with a write barrier.
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
);
509 // Replace the initializer.
510 Location loc
= init
->location();
511 Expression
* ref
= Expression::make_var_reference(no
, loc
);
513 Statement_inserter
inserter(this->gogo_
, var
, &this->statements_added_
);
514 Statement
* s
= this->gogo_
->assign_with_write_barrier(NULL
, NULL
, &inserter
,
516 this->statements_added_
.insert(s
);
518 var
->add_preinit_statement(this->gogo_
, s
);
521 return TRAVERSE_CONTINUE
;
524 // Insert write barriers for statements.
527 Write_barriers::statement(Block
* block
, size_t* pindex
, Statement
* s
)
529 if (this->statements_added_
.find(s
) != this->statements_added_
.end())
530 return TRAVERSE_SKIP_COMPONENTS
;
532 switch (s
->classification())
537 case Statement::STATEMENT_VARIABLE_DECLARATION
:
539 Variable_declaration_statement
* vds
=
540 s
->variable_declaration_statement();
541 Named_object
* no
= vds
->var();
542 Variable
* var
= no
->var_value();
544 // We may need to emit a write barrier for the initialization
547 // Nothing to do for a variable with no initializer.
548 Expression
* init
= var
->init();
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())
557 // If this is a pointer variable, and assigning through
558 // the initializer does not require a write barrier,
560 if (var
->type()->points_to() != NULL
561 && this->gogo_
->is_nonwb_pointer(init
, &this->nonwb_pointers_
))
562 this->nonwb_pointers_
.insert(no
);
567 // Nothing to do if the variable does not contain any pointers.
568 if (!var
->type()->has_pointer())
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())
575 if (var
->type()->points_to() != NULL
576 && !var
->type()->points_to()->in_heap())
579 // Otherwise initialize the variable with a write barrier.
581 Function
* function
= this->function_
;
582 Location loc
= init
->location();
583 Statement_inserter
inserter(block
, pindex
, &this->statements_added_
);
585 // Insert the variable declaration statement with no
586 // initializer, so that the variable exists.
590 // Create a statement that initializes the variable with a
592 Expression
* ref
= Expression::make_var_reference(no
, loc
);
593 Statement
* assign
= this->gogo_
->assign_with_write_barrier(function
,
598 this->statements_added_
.insert(assign
);
600 // Replace the old variable declaration statement with the new
602 block
->replace_statement(*pindex
, assign
);
606 case Statement::STATEMENT_ASSIGNMENT
:
608 Assignment_statement
* as
= s
->assignment_statement();
610 Expression
* lhs
= as
->lhs();
611 Expression
* rhs
= as
->rhs();
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
)
617 Named_object
* no
= lhsve
->named_object();
618 if (this->gogo_
->is_nonwb_pointer(rhs
, &this->nonwb_pointers_
))
619 this->nonwb_pointers_
.insert(no
);
621 this->nonwb_pointers_
.erase(no
);
624 if (as
->omit_write_barrier())
627 // We may need to emit a write barrier for the assignment.
629 if (!this->gogo_
->assign_needs_write_barrier(lhs
,
630 &this->nonwb_pointers_
))
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
,
643 this->statements_added_
.insert(assign
);
644 block
->replace_statement(*pindex
, assign
);
649 return TRAVERSE_CONTINUE
;
652 // The write barrier pass.
655 Gogo::add_write_barriers()
660 Mark_address_taken
mat(this);
661 this->traverse(&mat
);
663 if (this->compiling_runtime() && this->package_name() == "runtime")
665 this->propagate_writebarrierrec();
667 Check_escape
chk(this);
668 this->traverse(&chk
);
671 Write_barriers
wb(this);
675 // Return the runtime.writeBarrier variable.
678 Gogo::write_barrier_variable()
680 static Named_object
* write_barrier_var
;
681 if (write_barrier_var
== NULL
)
683 Location bloc
= Linemap::predeclared_location();
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
,
695 "alignme", uint64_type
);
697 Variable
* var
= new Variable(wb_type
, NULL
,
698 true, false, false, bloc
);
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",
708 return write_barrier_var
;
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.
716 Gogo::assign_needs_write_barrier(
718 Unordered_set(const Named_object
*)* nonwb_pointers
)
720 // Nothing to do if the variable does not contain any pointers.
721 if (!lhs
->type()->has_pointer())
724 // An assignment to a field or an array index is handled like an
725 // assignment to the struct.
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())
733 if (lhs
->type()->points_to() != NULL
734 && !lhs
->type()->points_to()->in_heap())
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();
742 bool in_heap
= false;
743 const Struct_field_list
* fields
= st
->fields();
744 for (Struct_field_list::const_iterator p
= fields
->begin();
748 Type
* ft
= p
->type();
749 if (!ft
->has_pointer())
753 if (ft
->points_to() != NULL
&& !ft
->points_to()->in_heap())
762 Field_reference_expression
* fre
= lhs
->field_reference_expression();
769 Array_index_expression
* aie
= lhs
->array_index_expression();
771 && aie
->end() == NULL
772 && !aie
->array()->type()->is_slice_type())
781 // Nothing to do for an assignment to a temporary.
782 if (lhs
->temporary_reference_expression() != NULL
)
785 // Nothing to do for an assignment to a sink.
786 if (lhs
->is_sink_expression())
789 // Nothing to do for an assignment to a local variable that is not
791 Var_expression
* ve
= lhs
->var_expression();
794 Named_object
* no
= ve
->named_object();
795 if (no
->is_variable())
797 Variable
* var
= no
->var_value();
798 if (!var
->is_global() && !var
->is_in_heap())
801 else if (no
->is_result_variable())
803 Result_variable
* rvar
= no
->result_var_value();
804 if (!rvar
->is_in_heap())
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();
813 && ue
->op() == OPERATOR_MULT
814 && this->is_nonwb_pointer(ue
->operand(), nonwb_pointers
))
817 // Write barrier needed in other cases.
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.
828 Gogo::is_nonwb_pointer(Expression
* expr
,
829 Unordered_set(const Named_object
*)* nonwb_pointers
)
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();
841 Var_expression
* ve
= expr
->var_expression();
843 && nonwb_pointers
!= NULL
844 && nonwb_pointers
->find(ve
->named_object()) != nonwb_pointers
->end())
847 Unary_expression
* ue
= expr
->unary_expression();
848 if (ue
== NULL
|| ue
->op() != OPERATOR_AND
)
850 if (this->assign_needs_write_barrier(ue
->operand(), nonwb_pointers
))
855 // Return a statement that sets LHS to RHS using a write barrier.
856 // ENCLOSING is the enclosing block.
859 Gogo::assign_with_write_barrier(Function
* function
, Block
* enclosing
,
860 Statement_inserter
* inserter
, Expression
* lhs
,
861 Expression
* rhs
, Location loc
)
863 if (function
!= NULL
&& (function
->pragmas() & GOPRAGMA_NOWRITEBARRIER
) != 0)
864 go_error_at(loc
, "write barrier prohibited");
866 Type
* type
= lhs
->type();
867 go_assert(type
->has_pointer());
870 if (lhs
->unary_expression() != NULL
871 && lhs
->unary_expression()->op() == OPERATOR_MULT
)
872 addr
= lhs
->unary_expression()->operand();
875 addr
= Expression::make_unary(OPERATOR_AND
, lhs
, loc
);
876 addr
->unary_expression()->set_does_not_escape();
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
);
882 if (!Type::are_identical(type
, rhs
->type(),
883 Type::COMPARE_ERRORS
| Type::COMPARE_TAGS
,
885 && rhs
->type()->interface_type() != NULL
886 && !rhs
->is_multi_eval_safe())
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
);
893 rhs
= Expression::convert_for_assignment(this, type
, rhs
, loc
);
894 Temporary_statement
* rhs_temp
= NULL
;
895 if (!rhs
->is_multi_eval_safe())
897 rhs_temp
= Statement::make_temporary(NULL
, rhs
, loc
);
898 inserter
->insert(rhs_temp
);
899 rhs
= Expression::make_temporary_reference(rhs_temp
, loc
);
903 Expression::make_dereference(lhs
, Expression::NIL_CHECK_DEFAULT
, loc
);
904 Statement
* assign
= Statement::make_assignment(indir
, rhs
, loc
);
906 lhs
= Expression::make_temporary_reference(lhs_temp
, loc
);
907 if (rhs_temp
!= NULL
)
908 rhs
= Expression::make_temporary_reference(rhs_temp
, loc
);
910 Type
* unsafe_ptr_type
= Type::make_pointer_type(Type::make_void_type());
911 lhs
= Expression::make_unsafe_cast(unsafe_ptr_type
, lhs
, loc
);
913 Type
* uintptr_type
= Type::lookup_integer_type("uintptr");
915 switch (type
->base()->classification())
920 case Type::TYPE_ERROR
:
923 case Type::TYPE_POINTER
:
924 case Type::TYPE_FUNCTION
:
926 case Type::TYPE_CHANNEL
:
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
);
934 case Type::TYPE_STRING
:
936 // Assign the length field directly.
938 Expression::make_string_info(indir
->copy(),
939 Expression::STRING_INFO_LENGTH
,
942 Expression::make_string_info(rhs
,
943 Expression::STRING_INFO_LENGTH
,
945 Statement
* as
= Statement::make_assignment(llen
, rlen
, loc
);
946 inserter
->insert(as
);
948 // Assign the data field with a write barrier.
950 Expression::make_string_info(indir
->copy(),
951 Expression::STRING_INFO_DATA
,
954 Expression::make_string_info(rhs
,
955 Expression::STRING_INFO_DATA
,
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
);
964 case Type::TYPE_INTERFACE
:
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
971 // Method tables are either statically created or persistently
973 // In all cases they don't need a write barrier.
975 Expression::make_interface_info(indir
->copy(),
976 Expression::INTERFACE_INFO_METHODS
,
979 Expression::make_interface_info(rhs
,
980 Expression::INTERFACE_INFO_METHODS
,
982 Statement
* as
= Statement::make_assignment(ltab
, rtab
, loc
);
983 inserter
->insert(as
);
985 // Assign the data field with a write barrier.
987 Expression::make_interface_info(indir
->copy(),
988 Expression::INTERFACE_INFO_OBJECT
,
991 Expression::make_interface_info(rhs
,
992 Expression::INTERFACE_INFO_OBJECT
,
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
);
1001 case Type::TYPE_ARRAY
:
1002 if (type
->is_slice_type())
1004 // Assign the lenth fields directly.
1006 Expression::make_slice_info(indir
->copy(),
1007 Expression::SLICE_INFO_LENGTH
,
1010 Expression::make_slice_info(rhs
,
1011 Expression::SLICE_INFO_LENGTH
,
1013 Statement
* as
= Statement::make_assignment(llen
, rlen
, loc
);
1014 inserter
->insert(as
);
1016 // Assign the capacity fields directly.
1018 Expression::make_slice_info(indir
->copy(),
1019 Expression::SLICE_INFO_CAPACITY
,
1022 Expression::make_slice_info(rhs
,
1023 Expression::SLICE_INFO_CAPACITY
,
1025 as
= Statement::make_assignment(lcap
, rcap
, loc
);
1026 inserter
->insert(as
);
1028 // Assign the data field with a write barrier.
1030 Expression::make_slice_info(indir
->copy(),
1031 Expression::SLICE_INFO_VALUE_POINTER
,
1034 Expression::make_slice_info(rhs
,
1035 Expression::SLICE_INFO_VALUE_POINTER
,
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
);
1045 case Type::TYPE_STRUCT
:
1046 if (type
->is_direct_iface_type())
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
);
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
),
1064 return this->check_write_barrier(enclosing
, assign
,
1065 Statement::make_statement(call
, false));
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.
1073 Gogo::check_write_barrier(Block
* enclosing
, Statement
* without
,
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
);
1093 Block
* then_block
= new Block(enclosing
, loc
);
1094 then_block
->add_statement(without
);
1096 Block
* else_block
= new Block(enclosing
, loc
);
1097 else_block
->add_statement(with
);
1099 return Statement::make_if_statement(cond
, then_block
, else_block
, loc
);