annotate gcc/go/gofrontend/wb.cc @ 158:494b0b89df80 default tip

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