annotate gcc/go/gofrontend/escape.cc @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 // escape.cc -- Go escape analysis (based on Go compiler algorithm).
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 // Copyright 2016 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 <limits>
kono
parents:
diff changeset
10 #include <stack>
kono
parents:
diff changeset
11 #include <sstream>
kono
parents:
diff changeset
12
kono
parents:
diff changeset
13 #include "gogo.h"
kono
parents:
diff changeset
14 #include "types.h"
kono
parents:
diff changeset
15 #include "expressions.h"
kono
parents:
diff changeset
16 #include "statements.h"
kono
parents:
diff changeset
17 #include "escape.h"
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
18 #include "lex.h"
111
kono
parents:
diff changeset
19 #include "ast-dump.h"
kono
parents:
diff changeset
20 #include "go-optimize.h"
kono
parents:
diff changeset
21 #include "go-diagnostics.h"
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
22 #include "go-sha1.h"
111
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 // class Node.
kono
parents:
diff changeset
25
kono
parents:
diff changeset
26 // Return the node's type, if it makes sense for it to have one.
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 Type*
kono
parents:
diff changeset
29 Node::type() const
kono
parents:
diff changeset
30 {
kono
parents:
diff changeset
31 if (this->object() != NULL
kono
parents:
diff changeset
32 && this->object()->is_variable())
kono
parents:
diff changeset
33 return this->object()->var_value()->type();
kono
parents:
diff changeset
34 else if (this->object() != NULL
kono
parents:
diff changeset
35 && this->object()->is_function())
kono
parents:
diff changeset
36 return this->object()->func_value()->type();
kono
parents:
diff changeset
37 else if (this->expr() != NULL)
kono
parents:
diff changeset
38 return this->expr()->type();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
39 else if (this->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
40 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
41 if (this->child()->type()->deref()->is_void_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
42 // This is a void*. The referred type can be actually any type,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
43 // which may also be pointer. We model it as another void*, so
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
44 // we don't lose pointer-ness.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
45 return this->child()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
46 else if (this->child()->type()->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
47 // We model "indirect" of a slice as dereferencing its pointer
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
48 // field (to get element). Use element type here.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
49 return this->child()->type()->array_type()->element_type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
50 else if (this->child()->type()->is_string_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
51 return Type::lookup_integer_type("uint8");
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
52 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
53 return this->child()->type()->deref();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
54 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
55 else if (this->statement() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
56 && this->statement()->temporary_statement() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
57 return this->statement()->temporary_statement()->type();
111
kono
parents:
diff changeset
58 else
kono
parents:
diff changeset
59 return NULL;
kono
parents:
diff changeset
60 }
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 // A helper for reporting; return this node's location.
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 Location
kono
parents:
diff changeset
65 Node::location() const
kono
parents:
diff changeset
66 {
kono
parents:
diff changeset
67 if (this->object() != NULL && !this->object()->is_sink())
kono
parents:
diff changeset
68 return this->object()->location();
kono
parents:
diff changeset
69 else if (this->expr() != NULL)
kono
parents:
diff changeset
70 return this->expr()->location();
kono
parents:
diff changeset
71 else if (this->statement() != NULL)
kono
parents:
diff changeset
72 return this->statement()->location();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
73 else if (this->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
74 return this->child()->location();
111
kono
parents:
diff changeset
75 else
kono
parents:
diff changeset
76 return Linemap::unknown_location();
kono
parents:
diff changeset
77 }
kono
parents:
diff changeset
78
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
79 // A helper for reporting; return the location where the underlying
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
80 // object is defined.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
81
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
82 Location
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
83 Node::definition_location() const
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
84 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
85 if (this->object() != NULL && !this->object()->is_sink())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
86 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
87 Named_object* no = this->object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
88 if (no->is_variable() || no->is_result_variable())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
89 return no->location();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
90 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
91 else if (this->expr() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
92 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
93 Var_expression* ve = this->expr()->var_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
94 if (ve != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
95 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
96 Named_object* no = ve->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
97 if (no->is_variable() || no->is_result_variable())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
98 return no->location();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
99 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
100 Enclosed_var_expression* eve = this->expr()->enclosed_var_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
101 if (eve != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
102 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
103 Named_object* no = eve->variable();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
104 if (no->is_variable() || no->is_result_variable())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
105 return no->location();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
106 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
107 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
108 return this->location();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
109 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
110
111
kono
parents:
diff changeset
111 // To match the cmd/gc debug output, strip away the packed prefixes on functions
kono
parents:
diff changeset
112 // and variable/expressions.
kono
parents:
diff changeset
113
kono
parents:
diff changeset
114 std::string
kono
parents:
diff changeset
115 strip_packed_prefix(Gogo* gogo, const std::string& s)
kono
parents:
diff changeset
116 {
kono
parents:
diff changeset
117 std::string packed_prefix = "." + gogo->pkgpath() + ".";
kono
parents:
diff changeset
118 std::string fmt = s;
kono
parents:
diff changeset
119 for (size_t pos = fmt.find(packed_prefix);
kono
parents:
diff changeset
120 pos != std::string::npos;
kono
parents:
diff changeset
121 pos = fmt.find(packed_prefix))
kono
parents:
diff changeset
122 fmt.erase(pos, packed_prefix.length());
kono
parents:
diff changeset
123 return fmt;
kono
parents:
diff changeset
124 }
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 // A helper for debugging; return this node's AST formatted string.
kono
parents:
diff changeset
127 // This is an implementation of gc's Nconv with obj.FmtShort.
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 std::string
kono
parents:
diff changeset
130 Node::ast_format(Gogo* gogo) const
kono
parents:
diff changeset
131 {
kono
parents:
diff changeset
132 std::ostringstream ss;
kono
parents:
diff changeset
133 if (this->is_sink())
kono
parents:
diff changeset
134 ss << ".sink";
kono
parents:
diff changeset
135 else if (this->object() != NULL)
kono
parents:
diff changeset
136 {
kono
parents:
diff changeset
137 Named_object* no = this->object();
kono
parents:
diff changeset
138 if (no->is_function() && no->func_value()->enclosing() != NULL)
kono
parents:
diff changeset
139 return "func literal";
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
140 ss << no->message_name();
111
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142 else if (this->expr() != NULL)
kono
parents:
diff changeset
143 {
kono
parents:
diff changeset
144 Expression* e = this->expr();
kono
parents:
diff changeset
145 bool is_call = e->call_expression() != NULL;
kono
parents:
diff changeset
146 if (is_call)
kono
parents:
diff changeset
147 e->call_expression()->fn();
kono
parents:
diff changeset
148 Func_expression* fe = e->func_expression();;
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 bool is_closure = fe != NULL && fe->closure() != NULL;
kono
parents:
diff changeset
151 if (is_closure)
kono
parents:
diff changeset
152 {
kono
parents:
diff changeset
153 if (is_call)
kono
parents:
diff changeset
154 return "(func literal)()";
kono
parents:
diff changeset
155 return "func literal";
kono
parents:
diff changeset
156 }
kono
parents:
diff changeset
157 Ast_dump_context::dump_to_stream(this->expr(), &ss);
kono
parents:
diff changeset
158 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
159 else if (this->statement() != NULL)
111
kono
parents:
diff changeset
160 {
kono
parents:
diff changeset
161 Statement* s = this->statement();
kono
parents:
diff changeset
162 Goto_unnamed_statement* unnamed = s->goto_unnamed_statement();
kono
parents:
diff changeset
163 if (unnamed != NULL)
kono
parents:
diff changeset
164 {
kono
parents:
diff changeset
165 Statement* derived = unnamed->unnamed_label()->derived_from();
kono
parents:
diff changeset
166 if (derived != NULL)
kono
parents:
diff changeset
167 {
kono
parents:
diff changeset
168 switch (derived->classification())
kono
parents:
diff changeset
169 {
kono
parents:
diff changeset
170 case Statement::STATEMENT_FOR:
kono
parents:
diff changeset
171 case Statement::STATEMENT_FOR_RANGE:
kono
parents:
diff changeset
172 return "for loop";
kono
parents:
diff changeset
173 break;
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 case Statement::STATEMENT_SWITCH:
kono
parents:
diff changeset
176 return "switch";
kono
parents:
diff changeset
177 break;
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 case Statement::STATEMENT_TYPE_SWITCH:
kono
parents:
diff changeset
180 return "type switch";
kono
parents:
diff changeset
181 break;
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 default:
kono
parents:
diff changeset
184 break;
kono
parents:
diff changeset
185 }
kono
parents:
diff changeset
186 }
kono
parents:
diff changeset
187 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
188 Temporary_statement* tmp = s->temporary_statement();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
189 if (tmp != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
190 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
191 // Temporary's format can never match gc's output, and
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
192 // temporaries are inserted differently anyway. We just
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
193 // print something convenient.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
194 ss << "tmp." << (uintptr_t) tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
195 if (tmp->init() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
196 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
197 ss << " [ = ";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
198 Ast_dump_context::dump_to_stream(tmp->init(), &ss);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
199 ss << " ]";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
200 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
201 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
202 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
203 Ast_dump_context::dump_to_stream(s, &ss);
111
kono
parents:
diff changeset
204 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
205 else if (this->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
206 return "*(" + this->child()->ast_format(gogo) + ")";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
207
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
208 std::string s = strip_packed_prefix(gogo, ss.str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
209
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
210 // trim trailing space
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
211 return s.substr(0, s.find_last_not_of(' ') + 1);
111
kono
parents:
diff changeset
212 }
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 // A helper for debugging; return this node's detailed format string.
kono
parents:
diff changeset
215 // This is an implementation of gc's Jconv with obj.FmtShort.
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 std::string
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
218 Node::details()
111
kono
parents:
diff changeset
219 {
kono
parents:
diff changeset
220 std::stringstream details;
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 if (!this->is_sink())
kono
parents:
diff changeset
223 details << " l(" << Linemap::location_to_line(this->location()) << ")";
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 bool is_varargs = false;
kono
parents:
diff changeset
226 bool is_address_taken = false;
kono
parents:
diff changeset
227 bool is_in_heap = false;
kono
parents:
diff changeset
228 bool is_assigned = false;
kono
parents:
diff changeset
229 std::string class_name;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 Expression* e = this->expr();
kono
parents:
diff changeset
232 Named_object* node_object = NULL;
kono
parents:
diff changeset
233 if (this->object() != NULL)
kono
parents:
diff changeset
234 node_object = this->object();
kono
parents:
diff changeset
235 else if (e != NULL && e->var_expression() != NULL)
kono
parents:
diff changeset
236 node_object = e->var_expression()->named_object();
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 if (node_object)
kono
parents:
diff changeset
239 {
kono
parents:
diff changeset
240 // TODO(cmang): For named variables and functions, we want to output
kono
parents:
diff changeset
241 // the function depth.
kono
parents:
diff changeset
242 if (node_object->is_variable())
kono
parents:
diff changeset
243 {
kono
parents:
diff changeset
244 Variable* var = node_object->var_value();
kono
parents:
diff changeset
245 is_varargs = var->is_varargs_parameter();
kono
parents:
diff changeset
246 is_address_taken = (var->is_address_taken()
kono
parents:
diff changeset
247 || var->is_non_escaping_address_taken());
kono
parents:
diff changeset
248 is_in_heap = var->is_in_heap();
kono
parents:
diff changeset
249 is_assigned = var->init() != NULL;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 if (var->is_global())
kono
parents:
diff changeset
252 class_name = "PEXTERN";
kono
parents:
diff changeset
253 else if (var->is_parameter())
kono
parents:
diff changeset
254 class_name = "PPARAM";
kono
parents:
diff changeset
255 else if (var->is_closure())
kono
parents:
diff changeset
256 class_name = "PPARAMREF";
kono
parents:
diff changeset
257 else
kono
parents:
diff changeset
258 class_name = "PAUTO";
kono
parents:
diff changeset
259 }
kono
parents:
diff changeset
260 else if (node_object->is_result_variable())
kono
parents:
diff changeset
261 class_name = "PPARAMOUT";
kono
parents:
diff changeset
262 else if (node_object->is_function()
kono
parents:
diff changeset
263 || node_object->is_function_declaration())
kono
parents:
diff changeset
264 class_name = "PFUNC";
kono
parents:
diff changeset
265 }
kono
parents:
diff changeset
266 else if (e != NULL && e->enclosed_var_expression() != NULL)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 Named_object* enclosed = e->enclosed_var_expression()->variable();
kono
parents:
diff changeset
269 if (enclosed->is_variable())
kono
parents:
diff changeset
270 {
kono
parents:
diff changeset
271 Variable* var = enclosed->var_value();
kono
parents:
diff changeset
272 is_address_taken = (var->is_address_taken()
kono
parents:
diff changeset
273 || var->is_non_escaping_address_taken());
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275 else
kono
parents:
diff changeset
276 {
kono
parents:
diff changeset
277 Result_variable* var = enclosed->result_var_value();
kono
parents:
diff changeset
278 is_address_taken = (var->is_address_taken()
kono
parents:
diff changeset
279 || var->is_non_escaping_address_taken());
kono
parents:
diff changeset
280 }
kono
parents:
diff changeset
281 class_name = "PPARAMREF";
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 if (!class_name.empty())
kono
parents:
diff changeset
285 {
kono
parents:
diff changeset
286 details << " class(" << class_name;
kono
parents:
diff changeset
287 if (is_in_heap)
kono
parents:
diff changeset
288 details << ",heap";
kono
parents:
diff changeset
289 details << ")";
kono
parents:
diff changeset
290 }
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 switch ((this->encoding() & ESCAPE_MASK))
kono
parents:
diff changeset
293 {
kono
parents:
diff changeset
294 case Node::ESCAPE_UNKNOWN:
kono
parents:
diff changeset
295 break;
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 case Node::ESCAPE_HEAP:
kono
parents:
diff changeset
298 details << " esc(h)";
kono
parents:
diff changeset
299 break;
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 case Node::ESCAPE_NONE:
kono
parents:
diff changeset
302 details << " esc(no)";
kono
parents:
diff changeset
303 break;
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 case Node::ESCAPE_NEVER:
kono
parents:
diff changeset
306 details << " esc(N)";
kono
parents:
diff changeset
307 break;
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 default:
kono
parents:
diff changeset
310 details << " esc(" << this->encoding() << ")";
kono
parents:
diff changeset
311 break;
kono
parents:
diff changeset
312 }
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 if (this->state_ != NULL && this->state_->loop_depth != 0)
kono
parents:
diff changeset
315 details << " ld(" << this->state_->loop_depth << ")";
kono
parents:
diff changeset
316
kono
parents:
diff changeset
317 if (is_varargs)
kono
parents:
diff changeset
318 details << " isddd(1)";
kono
parents:
diff changeset
319 if (is_address_taken)
kono
parents:
diff changeset
320 details << " addrtaken";
kono
parents:
diff changeset
321 if (is_assigned)
kono
parents:
diff changeset
322 details << " assigned";
kono
parents:
diff changeset
323
kono
parents:
diff changeset
324 return details.str();
kono
parents:
diff changeset
325 }
kono
parents:
diff changeset
326
kono
parents:
diff changeset
327 std::string
kono
parents:
diff changeset
328 Node::op_format() const
kono
parents:
diff changeset
329 {
kono
parents:
diff changeset
330 std::stringstream op;
kono
parents:
diff changeset
331 Ast_dump_context adc(&op, false);
kono
parents:
diff changeset
332 if (this->expr() != NULL)
kono
parents:
diff changeset
333 {
kono
parents:
diff changeset
334 Expression* e = this->expr();
kono
parents:
diff changeset
335 switch (e->classification())
kono
parents:
diff changeset
336 {
kono
parents:
diff changeset
337 case Expression::EXPRESSION_UNARY:
kono
parents:
diff changeset
338 adc.dump_operator(e->unary_expression()->op());
kono
parents:
diff changeset
339 break;
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 case Expression::EXPRESSION_BINARY:
kono
parents:
diff changeset
342 adc.dump_operator(e->binary_expression()->op());
kono
parents:
diff changeset
343 break;
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 case Expression::EXPRESSION_CALL:
kono
parents:
diff changeset
346 op << "function call";
kono
parents:
diff changeset
347 break;
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349 case Expression::EXPRESSION_FUNC_REFERENCE:
kono
parents:
diff changeset
350 if (e->func_expression()->is_runtime_function())
kono
parents:
diff changeset
351 {
kono
parents:
diff changeset
352 switch (e->func_expression()->runtime_code())
kono
parents:
diff changeset
353 {
kono
parents:
diff changeset
354 case Runtime::GOPANIC:
kono
parents:
diff changeset
355 op << "panic";
kono
parents:
diff changeset
356 break;
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 case Runtime::GROWSLICE:
kono
parents:
diff changeset
359 op << "append";
kono
parents:
diff changeset
360 break;
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 case Runtime::SLICECOPY:
kono
parents:
diff changeset
363 case Runtime::SLICESTRINGCOPY:
kono
parents:
diff changeset
364 case Runtime::TYPEDSLICECOPY:
kono
parents:
diff changeset
365 op << "copy";
kono
parents:
diff changeset
366 break;
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 case Runtime::MAKECHAN:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
369 case Runtime::MAKECHAN64:
111
kono
parents:
diff changeset
370 case Runtime::MAKEMAP:
kono
parents:
diff changeset
371 case Runtime::MAKESLICE:
kono
parents:
diff changeset
372 case Runtime::MAKESLICE64:
kono
parents:
diff changeset
373 op << "make";
kono
parents:
diff changeset
374 break;
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 case Runtime::DEFERPROC:
kono
parents:
diff changeset
377 op << "defer";
kono
parents:
diff changeset
378 break;
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 case Runtime::GORECOVER:
kono
parents:
diff changeset
381 op << "recover";
kono
parents:
diff changeset
382 break;
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 case Runtime::CLOSE:
kono
parents:
diff changeset
385 op << "close";
kono
parents:
diff changeset
386 break;
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 default:
kono
parents:
diff changeset
389 break;
kono
parents:
diff changeset
390 }
kono
parents:
diff changeset
391 }
kono
parents:
diff changeset
392 break;
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 case Expression::EXPRESSION_ALLOCATION:
kono
parents:
diff changeset
395 op << "new";
kono
parents:
diff changeset
396 break;
kono
parents:
diff changeset
397
kono
parents:
diff changeset
398 case Expression::EXPRESSION_RECEIVE:
kono
parents:
diff changeset
399 op << "<-";
kono
parents:
diff changeset
400 break;
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 default:
kono
parents:
diff changeset
403 break;
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405 }
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 if (this->statement() != NULL)
kono
parents:
diff changeset
408 {
kono
parents:
diff changeset
409 switch (this->statement()->classification())
kono
parents:
diff changeset
410 {
kono
parents:
diff changeset
411 case Statement::STATEMENT_DEFER:
kono
parents:
diff changeset
412 op << "defer";
kono
parents:
diff changeset
413 break;
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 case Statement::STATEMENT_RETURN:
kono
parents:
diff changeset
416 op << "return";
kono
parents:
diff changeset
417 break;
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 default:
kono
parents:
diff changeset
420 break;
kono
parents:
diff changeset
421 }
kono
parents:
diff changeset
422 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
423 if (this->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
424 op << "*";
111
kono
parents:
diff changeset
425 return op.str();
kono
parents:
diff changeset
426 }
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 // Return this node's state, creating it if has not been initialized.
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 Node::Escape_state*
kono
parents:
diff changeset
431 Node::state(Escape_context* context, Named_object* fn)
kono
parents:
diff changeset
432 {
kono
parents:
diff changeset
433 if (this->state_ == NULL)
kono
parents:
diff changeset
434 {
kono
parents:
diff changeset
435 if (this->expr() != NULL && this->expr()->var_expression() != NULL)
kono
parents:
diff changeset
436 {
kono
parents:
diff changeset
437 // Tie state of variable references to underlying variables.
kono
parents:
diff changeset
438 Named_object* var_no = this->expr()->var_expression()->named_object();
kono
parents:
diff changeset
439 Node* var_node = Node::make_node(var_no);
kono
parents:
diff changeset
440 this->state_ = var_node->state(context, fn);
kono
parents:
diff changeset
441 }
kono
parents:
diff changeset
442 else
kono
parents:
diff changeset
443 {
kono
parents:
diff changeset
444 this->state_ = new Node::Escape_state;
kono
parents:
diff changeset
445 if (fn == NULL)
kono
parents:
diff changeset
446 fn = context->current_function();
kono
parents:
diff changeset
447
kono
parents:
diff changeset
448 this->state_->fn = fn;
kono
parents:
diff changeset
449 }
kono
parents:
diff changeset
450 }
kono
parents:
diff changeset
451 go_assert(this->state_ != NULL);
kono
parents:
diff changeset
452 return this->state_;
kono
parents:
diff changeset
453 }
kono
parents:
diff changeset
454
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
455 Node::~Node()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
456 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
457 if (this->state_ != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
458 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
459 if (this->expr() == NULL || this->expr()->var_expression() == NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
460 // Var expression Node is excluded since it shares state with the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
461 // underlying var Node.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
462 delete this->state_;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
463 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
464 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
465
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
466 int
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
467 Node::encoding()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
468 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
469 if (this->expr() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
470 && this->expr()->var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
471 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
472 // Get the underlying object's encoding.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
473 Named_object* no = this->expr()->var_expression()->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
474 int enc = Node::make_node(no)->encoding();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
475 this->encoding_ = enc;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
476 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
477 return this->encoding_;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
478 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
479
111
kono
parents:
diff changeset
480 void
kono
parents:
diff changeset
481 Node::set_encoding(int enc)
kono
parents:
diff changeset
482 {
kono
parents:
diff changeset
483 this->encoding_ = enc;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
484 if (this->expr() != NULL)
111
kono
parents:
diff changeset
485 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
486 if (this->expr()->var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
487 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
488 // Set underlying object as well.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
489 Named_object* no = this->expr()->var_expression()->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
490 Node::make_node(no)->set_encoding(enc);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
491 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
492 else if (this->expr()->func_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
493 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
494 // Propagate the escape state to the underlying
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
495 // closure (heap expression).
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
496 Expression* closure = this->expr()->func_expression()->closure();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
497 if (closure != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
498 Node::make_node(closure)->set_encoding(enc);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
499 }
111
kono
parents:
diff changeset
500 }
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 bool
kono
parents:
diff changeset
504 Node::is_big(Escape_context* context) const
kono
parents:
diff changeset
505 {
kono
parents:
diff changeset
506 Type* t = this->type();
kono
parents:
diff changeset
507 if (t == NULL
kono
parents:
diff changeset
508 || t->is_call_multiple_result_type()
kono
parents:
diff changeset
509 || t->is_sink_type()
kono
parents:
diff changeset
510 || t->is_void_type()
kono
parents:
diff changeset
511 || t->is_abstract())
kono
parents:
diff changeset
512 return false;
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 int64_t size;
kono
parents:
diff changeset
515 bool ok = t->backend_type_size(context->gogo(), &size);
kono
parents:
diff changeset
516 bool big = ok && (size < 0 || size > 10 * 1024 * 1024);
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 if (this->expr() != NULL)
kono
parents:
diff changeset
519 {
kono
parents:
diff changeset
520 if (this->expr()->allocation_expression() != NULL)
kono
parents:
diff changeset
521 {
kono
parents:
diff changeset
522 ok = t->deref()->backend_type_size(context->gogo(), &size);
kono
parents:
diff changeset
523 big = big || size <= 0 || size >= (1 << 16);
kono
parents:
diff changeset
524 }
kono
parents:
diff changeset
525 else if (this->expr()->call_expression() != NULL)
kono
parents:
diff changeset
526 {
kono
parents:
diff changeset
527 Call_expression* call = this->expr()->call_expression();
kono
parents:
diff changeset
528 Func_expression* fn = call->fn()->func_expression();
kono
parents:
diff changeset
529 if (fn != NULL
kono
parents:
diff changeset
530 && fn->is_runtime_function()
kono
parents:
diff changeset
531 && (fn->runtime_code() == Runtime::MAKESLICE
kono
parents:
diff changeset
532 || fn->runtime_code() == Runtime::MAKESLICE64))
kono
parents:
diff changeset
533 {
kono
parents:
diff changeset
534 // Second argument is length.
kono
parents:
diff changeset
535 Expression_list::iterator p = call->args()->begin();
kono
parents:
diff changeset
536 ++p;
kono
parents:
diff changeset
537
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
538 Expression* e = *p;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
539 if (e->temporary_reference_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
540 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
541 Temporary_reference_expression* tre = e->temporary_reference_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
542 if (tre->statement() != NULL && tre->statement()->init() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
543 e = tre->statement()->init();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
544 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
545
111
kono
parents:
diff changeset
546 Numeric_constant nc;
kono
parents:
diff changeset
547 unsigned long v;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
548 if (e->numeric_constant_value(&nc)
111
kono
parents:
diff changeset
549 && nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_VALID)
kono
parents:
diff changeset
550 big = big || v >= (1 << 16);
kono
parents:
diff changeset
551 }
kono
parents:
diff changeset
552 }
kono
parents:
diff changeset
553 }
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 return big;
kono
parents:
diff changeset
556 }
kono
parents:
diff changeset
557
kono
parents:
diff changeset
558 bool
kono
parents:
diff changeset
559 Node::is_sink() const
kono
parents:
diff changeset
560 {
kono
parents:
diff changeset
561 if (this->object() != NULL
kono
parents:
diff changeset
562 && this->object()->is_sink())
kono
parents:
diff changeset
563 return true;
kono
parents:
diff changeset
564 else if (this->expr() != NULL
kono
parents:
diff changeset
565 && this->expr()->is_sink_expression())
kono
parents:
diff changeset
566 return true;
kono
parents:
diff changeset
567 return false;
kono
parents:
diff changeset
568 }
kono
parents:
diff changeset
569
kono
parents:
diff changeset
570 std::map<Named_object*, Node*> Node::objects;
kono
parents:
diff changeset
571 std::map<Expression*, Node*> Node::expressions;
kono
parents:
diff changeset
572 std::map<Statement*, Node*> Node::statements;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
573 std::vector<Node*> Node::indirects;
111
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 // Make a object node or return a cached node for this object.
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 Node*
kono
parents:
diff changeset
578 Node::make_node(Named_object* no)
kono
parents:
diff changeset
579 {
kono
parents:
diff changeset
580 if (Node::objects.find(no) != Node::objects.end())
kono
parents:
diff changeset
581 return Node::objects[no];
kono
parents:
diff changeset
582
kono
parents:
diff changeset
583 Node* n = new Node(no);
kono
parents:
diff changeset
584 std::pair<Named_object*, Node*> val(no, n);
kono
parents:
diff changeset
585 Node::objects.insert(val);
kono
parents:
diff changeset
586 return n;
kono
parents:
diff changeset
587 }
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 // Make an expression node or return a cached node for this expression.
kono
parents:
diff changeset
590
kono
parents:
diff changeset
591 Node*
kono
parents:
diff changeset
592 Node::make_node(Expression* e)
kono
parents:
diff changeset
593 {
kono
parents:
diff changeset
594 if (Node::expressions.find(e) != Node::expressions.end())
kono
parents:
diff changeset
595 return Node::expressions[e];
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 Node* n = new Node(e);
kono
parents:
diff changeset
598 std::pair<Expression*, Node*> val(e, n);
kono
parents:
diff changeset
599 Node::expressions.insert(val);
kono
parents:
diff changeset
600 return n;
kono
parents:
diff changeset
601 }
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 // Make a statement node or return a cached node for this statement.
kono
parents:
diff changeset
604
kono
parents:
diff changeset
605 Node*
kono
parents:
diff changeset
606 Node::make_node(Statement* s)
kono
parents:
diff changeset
607 {
kono
parents:
diff changeset
608 if (Node::statements.find(s) != Node::statements.end())
kono
parents:
diff changeset
609 return Node::statements[s];
kono
parents:
diff changeset
610
kono
parents:
diff changeset
611 Node* n = new Node(s);
kono
parents:
diff changeset
612 std::pair<Statement*, Node*> val(s, n);
kono
parents:
diff changeset
613 Node::statements.insert(val);
kono
parents:
diff changeset
614 return n;
kono
parents:
diff changeset
615 }
kono
parents:
diff changeset
616
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
617 // Make an indirect node with given child.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
618
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
619 Node*
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
620 Node::make_indirect_node(Node* child)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
621 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
622 Node* n = new Node(child);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
623 Node::indirects.push_back(n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
624 return n;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
625 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
626
111
kono
parents:
diff changeset
627 // Returns the maximum of an exisiting escape value
kono
parents:
diff changeset
628 // (and its additional parameter flow flags) and a new escape type.
kono
parents:
diff changeset
629
kono
parents:
diff changeset
630 int
kono
parents:
diff changeset
631 Node::max_encoding(int e, int etype)
kono
parents:
diff changeset
632 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
633 if ((e & ESCAPE_MASK) > etype)
111
kono
parents:
diff changeset
634 return e;
kono
parents:
diff changeset
635 if (etype == Node::ESCAPE_NONE || etype == Node::ESCAPE_RETURN)
kono
parents:
diff changeset
636 return (e & ~ESCAPE_MASK) | etype;
kono
parents:
diff changeset
637 return etype;
kono
parents:
diff changeset
638 }
kono
parents:
diff changeset
639
kono
parents:
diff changeset
640 // Return a modified encoding for an input parameter that flows into an
kono
parents:
diff changeset
641 // output parameter.
kono
parents:
diff changeset
642
kono
parents:
diff changeset
643 int
kono
parents:
diff changeset
644 Node::note_inout_flows(int e, int index, Level level)
kono
parents:
diff changeset
645 {
kono
parents:
diff changeset
646 // Flow+level is encoded in two bits.
kono
parents:
diff changeset
647 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel.
kono
parents:
diff changeset
648 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional
kono
parents:
diff changeset
649 // information would be useful.
kono
parents:
diff changeset
650 if (level.value() <= 0 && level.suffix_value() > 0)
kono
parents:
diff changeset
651 return Node::max_encoding(e|ESCAPE_CONTENT_ESCAPES, Node::ESCAPE_NONE);
kono
parents:
diff changeset
652 if (level.value() < 0)
kono
parents:
diff changeset
653 return Node::ESCAPE_HEAP;
kono
parents:
diff changeset
654 if (level.value() > ESCAPE_MAX_ENCODED_LEVEL)
kono
parents:
diff changeset
655 level = Level::From(ESCAPE_MAX_ENCODED_LEVEL);
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 int encoded = level.value() + 1;
kono
parents:
diff changeset
658 int shift = ESCAPE_BITS_PER_OUTPUT_IN_TAG * index + ESCAPE_RETURN_BITS;
kono
parents:
diff changeset
659 int old = (e >> shift) & ESCAPE_BITS_MASK_FOR_TAG;
kono
parents:
diff changeset
660 if (old == 0
kono
parents:
diff changeset
661 || (encoded != 0 && encoded < old))
kono
parents:
diff changeset
662 old = encoded;
kono
parents:
diff changeset
663
kono
parents:
diff changeset
664 int encoded_flow = old << shift;
kono
parents:
diff changeset
665 if (((encoded_flow >> shift) & ESCAPE_BITS_MASK_FOR_TAG) != old)
kono
parents:
diff changeset
666 {
kono
parents:
diff changeset
667 // Failed to encode. Put this on the heap.
kono
parents:
diff changeset
668 return Node::ESCAPE_HEAP;
kono
parents:
diff changeset
669 }
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 return (e & ~(ESCAPE_BITS_MASK_FOR_TAG << shift)) | encoded_flow;
kono
parents:
diff changeset
672 }
kono
parents:
diff changeset
673
kono
parents:
diff changeset
674 // Class Escape_context.
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 Escape_context::Escape_context(Gogo* gogo, bool recursive)
kono
parents:
diff changeset
677 : gogo_(gogo), current_function_(NULL), recursive_(recursive),
kono
parents:
diff changeset
678 sink_(Node::make_node(Named_object::make_sink())), loop_depth_(0),
kono
parents:
diff changeset
679 flood_id_(0), pdepth_(0)
kono
parents:
diff changeset
680 {
kono
parents:
diff changeset
681 // The sink always escapes to heap and strictly lives outside of the
kono
parents:
diff changeset
682 // current function i.e. loop_depth == -1.
kono
parents:
diff changeset
683 Node::Escape_state* state = this->sink_->state(this, NULL);
kono
parents:
diff changeset
684 state->loop_depth = -1;
kono
parents:
diff changeset
685 }
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687 std::string
kono
parents:
diff changeset
688 debug_function_name(Named_object* fn)
kono
parents:
diff changeset
689 {
kono
parents:
diff changeset
690 if (fn == NULL)
kono
parents:
diff changeset
691 return "<S>";
kono
parents:
diff changeset
692
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
693 if (!fn->is_function())
111
kono
parents:
diff changeset
694 return Gogo::unpack_hidden_name(fn->name());
kono
parents:
diff changeset
695
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
696 std::string fnname = Gogo::unpack_hidden_name(fn->name());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
697 if (fn->func_value()->is_method())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
698 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
699 // Methods in gc compiler are named "T.m" or "(*T).m" where
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
700 // T is the receiver type. Add the receiver here.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
701 Type* rt = fn->func_value()->type()->receiver()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
702 switch (rt->classification())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
703 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
704 case Type::TYPE_NAMED:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
705 fnname = rt->named_type()->name() + "." + fnname;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
706 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
707
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
708 case Type::TYPE_POINTER:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
709 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
710 Named_type* nt = rt->points_to()->named_type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
711 if (nt != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
712 fnname = "(*" + nt->name() + ")." + fnname;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
713 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
714 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
715
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
716 default:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
717 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
718 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
719 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
720
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
721 return fnname;
111
kono
parents:
diff changeset
722 }
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 // Return the name of the current function.
kono
parents:
diff changeset
725
kono
parents:
diff changeset
726 std::string
kono
parents:
diff changeset
727 Escape_context::current_function_name() const
kono
parents:
diff changeset
728 {
kono
parents:
diff changeset
729 return debug_function_name(this->current_function_);
kono
parents:
diff changeset
730 }
kono
parents:
diff changeset
731
kono
parents:
diff changeset
732 // Initialize the dummy return values for this Node N using the results
kono
parents:
diff changeset
733 // in FNTYPE.
kono
parents:
diff changeset
734
kono
parents:
diff changeset
735 void
kono
parents:
diff changeset
736 Escape_context::init_retvals(Node* n, Function_type* fntype)
kono
parents:
diff changeset
737 {
kono
parents:
diff changeset
738 if (fntype == NULL || fntype->results() == NULL)
kono
parents:
diff changeset
739 return;
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 Node::Escape_state* state = n->state(this, NULL);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
742 state->retvals.clear();
111
kono
parents:
diff changeset
743 Location loc = n->location();
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 int i = 0;
kono
parents:
diff changeset
746 char buf[50];
kono
parents:
diff changeset
747 for (Typed_identifier_list::const_iterator p = fntype->results()->begin();
kono
parents:
diff changeset
748 p != fntype->results()->end();
kono
parents:
diff changeset
749 ++p, ++i)
kono
parents:
diff changeset
750 {
kono
parents:
diff changeset
751 snprintf(buf, sizeof buf, ".out%d", i);
kono
parents:
diff changeset
752 Variable* dummy_var = new Variable(p->type(), NULL, false, false,
kono
parents:
diff changeset
753 false, loc);
kono
parents:
diff changeset
754 dummy_var->set_is_used();
kono
parents:
diff changeset
755 Named_object* dummy_no =
kono
parents:
diff changeset
756 Named_object::make_variable(buf, NULL, dummy_var);
kono
parents:
diff changeset
757 Node* dummy_node = Node::make_node(dummy_no);
kono
parents:
diff changeset
758 // Initialize the state of the dummy output node.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
759 Node::Escape_state* dummy_node_state = dummy_node->state(this, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
760 dummy_node_state->loop_depth = this->loop_depth_;
111
kono
parents:
diff changeset
761
kono
parents:
diff changeset
762 // Add dummy node to the retvals of n.
kono
parents:
diff changeset
763 state->retvals.push_back(dummy_node);
kono
parents:
diff changeset
764 }
kono
parents:
diff changeset
765 }
kono
parents:
diff changeset
766
kono
parents:
diff changeset
767
kono
parents:
diff changeset
768 // Apply an indirection to N and return the result.
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 Node*
kono
parents:
diff changeset
771 Escape_context::add_dereference(Node* n)
kono
parents:
diff changeset
772 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
773 Expression* e = n->expr();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
774 Location loc = n->location();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
775 Node* ind;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
776 if (e != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
777 && e->type()->points_to() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
778 && !e->type()->points_to()->is_void_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
779 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
780 // We don't dereference void*, which can be actually any pointer type.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
781 Expression* deref_expr = Expression::make_unary(OPERATOR_MULT, e, loc);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
782 ind = Node::make_node(deref_expr);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
783 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
784 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
785 // The gc compiler simply makes an OIND node. We can't do it
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
786 // for non-pointer type because that will result in a type error.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
787 // Instead, we model this by making a node with a special flavor.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
788 ind = Node::make_indirect_node(n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
789
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
790 // Initialize the state.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
791 Node::Escape_state* state = ind->state(this, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
792 state->loop_depth = n->state(this, NULL)->loop_depth;
111
kono
parents:
diff changeset
793 return ind;
kono
parents:
diff changeset
794 }
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 void
kono
parents:
diff changeset
797 Escape_context::track(Node* n)
kono
parents:
diff changeset
798 {
kono
parents:
diff changeset
799 n->set_encoding(Node::ESCAPE_NONE);
kono
parents:
diff changeset
800 // Initialize this node's state if it hasn't been encountered
kono
parents:
diff changeset
801 // before.
kono
parents:
diff changeset
802 Node::Escape_state* state = n->state(this, NULL);
kono
parents:
diff changeset
803 state->loop_depth = this->loop_depth_;
kono
parents:
diff changeset
804
kono
parents:
diff changeset
805 this->noesc_.push_back(n);
kono
parents:
diff changeset
806 }
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808 // Return the string representation of an escapement encoding.
kono
parents:
diff changeset
809
kono
parents:
diff changeset
810 std::string
kono
parents:
diff changeset
811 Escape_note::make_tag(int encoding)
kono
parents:
diff changeset
812 {
kono
parents:
diff changeset
813 char buf[50];
kono
parents:
diff changeset
814 snprintf(buf, sizeof buf, "esc:0x%x", encoding);
kono
parents:
diff changeset
815 return buf;
kono
parents:
diff changeset
816 }
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 // Return the escapement encoding for a string tag.
kono
parents:
diff changeset
819
kono
parents:
diff changeset
820 int
kono
parents:
diff changeset
821 Escape_note::parse_tag(std::string* tag)
kono
parents:
diff changeset
822 {
kono
parents:
diff changeset
823 if (tag == NULL || tag->substr(0, 4) != "esc:")
kono
parents:
diff changeset
824 return Node::ESCAPE_UNKNOWN;
kono
parents:
diff changeset
825 int encoding = (int)strtol(tag->substr(4).c_str(), NULL, 0);
kono
parents:
diff changeset
826 if (encoding == 0)
kono
parents:
diff changeset
827 return Node::ESCAPE_UNKNOWN;
kono
parents:
diff changeset
828 return encoding;
kono
parents:
diff changeset
829 }
kono
parents:
diff changeset
830
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 // The -fgo-optimize-alloc flag activates this escape analysis.
kono
parents:
diff changeset
833
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
834 Go_optimize optimize_allocation_flag("allocs", true);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
835
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
836 // A helper function to compute whether a function name has a
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
837 // matching hash value.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
838
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
839 static bool
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
840 escape_hash_match(std::string suffix, std::string name)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
841 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
842 if (suffix.empty())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
843 return true;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
844 if (suffix.at(0) == '-')
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
845 return !escape_hash_match(suffix.substr(1), name);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
846
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
847 const char* p = name.c_str();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
848 Go_sha1_helper* sha1_helper = go_create_sha1_helper();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
849 sha1_helper->process_bytes(p, strlen(p));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
850 std::string s = sha1_helper->finish();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
851 delete sha1_helper;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
852
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
853 int j = suffix.size() - 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
854 for (int i = s.size() - 1; i >= 0; i--)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
855 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
856 char c = s.at(i);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
857 for (int k = 0; k < 8; k++, j--, c>>=1)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
858 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
859 if (j < 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
860 return true;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
861 char bit = suffix.at(j) - '0';
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
862 if ((c&1) != bit)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
863 return false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
864 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
865 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
866 return false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
867 }
111
kono
parents:
diff changeset
868
kono
parents:
diff changeset
869 // Analyze the program flow for escape information.
kono
parents:
diff changeset
870
kono
parents:
diff changeset
871 void
kono
parents:
diff changeset
872 Gogo::analyze_escape()
kono
parents:
diff changeset
873 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
874 if (saw_errors())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
875 return;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
876
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
877 if (!optimize_allocation_flag.is_enabled()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
878 && !this->compiling_runtime())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
879 // We always run escape analysis when compiling runtime.
111
kono
parents:
diff changeset
880 return;
kono
parents:
diff changeset
881
kono
parents:
diff changeset
882 // Discover strongly connected groups of functions to analyze for escape
kono
parents:
diff changeset
883 // information in this package.
kono
parents:
diff changeset
884 this->discover_analysis_sets();
kono
parents:
diff changeset
885
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
886 if (!this->debug_escape_hash().empty())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
887 std::cerr << "debug-escape-hash " << this->debug_escape_hash() << "\n";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
888
111
kono
parents:
diff changeset
889 for (std::vector<Analysis_set>::iterator p = this->analysis_sets_.begin();
kono
parents:
diff changeset
890 p != this->analysis_sets_.end();
kono
parents:
diff changeset
891 ++p)
kono
parents:
diff changeset
892 {
kono
parents:
diff changeset
893 std::vector<Named_object*> stack = p->first;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
894
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
895 if (!this->debug_escape_hash().empty())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
896 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
897 bool match = false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
898 for (std::vector<Named_object*>::const_iterator fn = stack.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
899 fn != stack.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
900 ++fn)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
901 match = match || escape_hash_match(this->debug_escape_hash(), (*fn)->message_name());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
902 if (!match)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
903 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
904 // Escape analysis won't run on these functions, but still
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
905 // need to tag them, so the caller knows.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
906 for (std::vector<Named_object*>::iterator fn = stack.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
907 fn != stack.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
908 ++fn)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
909 if ((*fn)->is_function())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
910 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
911 Function_type* fntype = (*fn)->func_value()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
912 fntype->set_is_tagged();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
913
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
914 std::cerr << "debug-escape-hash disables " << debug_function_name(*fn) << "\n";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
915 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
916
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
917 continue;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
918 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
919 for (std::vector<Named_object*>::const_iterator fn = stack.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
920 fn != stack.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
921 ++fn)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
922 if ((*fn)->is_function())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
923 std::cerr << "debug-escape-hash triggers " << debug_function_name(*fn) << "\n";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
924 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
925
111
kono
parents:
diff changeset
926 Escape_context* context = new Escape_context(this, p->second);
kono
parents:
diff changeset
927
kono
parents:
diff changeset
928 // Analyze the flow of each function; build the connection graph.
kono
parents:
diff changeset
929 // This is the assign phase.
kono
parents:
diff changeset
930 for (std::vector<Named_object*>::reverse_iterator fn = stack.rbegin();
kono
parents:
diff changeset
931 fn != stack.rend();
kono
parents:
diff changeset
932 ++fn)
kono
parents:
diff changeset
933 {
kono
parents:
diff changeset
934 context->set_current_function(*fn);
kono
parents:
diff changeset
935 this->assign_connectivity(context, *fn);
kono
parents:
diff changeset
936 }
kono
parents:
diff changeset
937
kono
parents:
diff changeset
938 // Propagate levels across each dst. This is the flood phase.
kono
parents:
diff changeset
939 std::set<Node*> dsts = context->dsts();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
940 Unordered_map(Node*, int) escapes;
111
kono
parents:
diff changeset
941 for (std::set<Node*>::iterator n = dsts.begin();
kono
parents:
diff changeset
942 n != dsts.end();
kono
parents:
diff changeset
943 ++n)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
944 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
945 escapes[*n] = (*n)->encoding();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
946 this->propagate_escape(context, *n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
947 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
948 for (;;)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
949 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
950 // Reflood if the roots' escape states increase. Run until fix point.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
951 // This is rare.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
952 bool done = true;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
953 for (std::set<Node*>::iterator n = dsts.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
954 n != dsts.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
955 ++n)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
956 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
957 if ((*n)->object() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
958 && ((*n)->expr() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
959 || ((*n)->expr()->var_expression() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
960 && (*n)->expr()->enclosed_var_expression() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
961 && (*n)->expr()->func_expression() == NULL)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
962 continue;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
963 if (escapes[*n] != (*n)->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
964 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
965 done = false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
966 if (this->debug_escape_level() > 2)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
967 go_inform((*n)->location(), "Reflooding %s %s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
968 debug_function_name((*n)->state(context, NULL)->fn).c_str(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
969 (*n)->ast_format(this).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
970 escapes[*n] = (*n)->encoding();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
971 this->propagate_escape(context, *n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
972 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
973 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
974 if (done)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
975 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
976 }
111
kono
parents:
diff changeset
977
kono
parents:
diff changeset
978 // Tag each exported function's parameters with escape information.
kono
parents:
diff changeset
979 for (std::vector<Named_object*>::iterator fn = stack.begin();
kono
parents:
diff changeset
980 fn != stack.end();
kono
parents:
diff changeset
981 ++fn)
kono
parents:
diff changeset
982 this->tag_function(context, *fn);
kono
parents:
diff changeset
983
kono
parents:
diff changeset
984 if (this->debug_escape_level() != 0)
kono
parents:
diff changeset
985 {
kono
parents:
diff changeset
986 std::vector<Node*> noesc = context->non_escaping_nodes();
kono
parents:
diff changeset
987 for (std::vector<Node*>::const_iterator n = noesc.begin();
kono
parents:
diff changeset
988 n != noesc.end();
kono
parents:
diff changeset
989 ++n)
kono
parents:
diff changeset
990 {
kono
parents:
diff changeset
991 Node::Escape_state* state = (*n)->state(context, NULL);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
992 if ((*n)->encoding() == Node::ESCAPE_NONE)
111
kono
parents:
diff changeset
993 go_inform((*n)->location(), "%s %s does not escape",
kono
parents:
diff changeset
994 strip_packed_prefix(this, debug_function_name(state->fn)).c_str(),
kono
parents:
diff changeset
995 (*n)->ast_format(this).c_str());
kono
parents:
diff changeset
996 }
kono
parents:
diff changeset
997 }
kono
parents:
diff changeset
998 delete context;
kono
parents:
diff changeset
999 }
kono
parents:
diff changeset
1000 }
kono
parents:
diff changeset
1001
kono
parents:
diff changeset
1002 // Traverse the program, discovering the functions that are roots of strongly
kono
parents:
diff changeset
1003 // connected components. The goal of this phase to produce a set of functions
kono
parents:
diff changeset
1004 // that must be analyzed in order.
kono
parents:
diff changeset
1005
kono
parents:
diff changeset
1006 class Escape_analysis_discover : public Traverse
kono
parents:
diff changeset
1007 {
kono
parents:
diff changeset
1008 public:
kono
parents:
diff changeset
1009 Escape_analysis_discover(Gogo* gogo)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1010 : Traverse(traverse_functions | traverse_func_declarations),
111
kono
parents:
diff changeset
1011 gogo_(gogo), component_ids_()
kono
parents:
diff changeset
1012 { }
kono
parents:
diff changeset
1013
kono
parents:
diff changeset
1014 int
kono
parents:
diff changeset
1015 function(Named_object*);
kono
parents:
diff changeset
1016
kono
parents:
diff changeset
1017 int
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1018 function_declaration(Named_object*);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1019
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1020 int
111
kono
parents:
diff changeset
1021 visit(Named_object*);
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 int
kono
parents:
diff changeset
1024 visit_code(Named_object*, int);
kono
parents:
diff changeset
1025
kono
parents:
diff changeset
1026 private:
kono
parents:
diff changeset
1027 // A counter used to generate the ID for the function node in the graph.
kono
parents:
diff changeset
1028 static int id;
kono
parents:
diff changeset
1029
kono
parents:
diff changeset
1030 // Type used to map functions to an ID in a graph of connected components.
kono
parents:
diff changeset
1031 typedef Unordered_map(Named_object*, int) Component_ids;
kono
parents:
diff changeset
1032
kono
parents:
diff changeset
1033 // The Go IR.
kono
parents:
diff changeset
1034 Gogo* gogo_;
kono
parents:
diff changeset
1035 // The list of functions encountered during connected component discovery.
kono
parents:
diff changeset
1036 Component_ids component_ids_;
kono
parents:
diff changeset
1037 // The stack of functions that this component consists of.
kono
parents:
diff changeset
1038 std::stack<Named_object*> stack_;
kono
parents:
diff changeset
1039 };
kono
parents:
diff changeset
1040
kono
parents:
diff changeset
1041 int Escape_analysis_discover::id = 0;
kono
parents:
diff changeset
1042
kono
parents:
diff changeset
1043 // Visit each function.
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 int
kono
parents:
diff changeset
1046 Escape_analysis_discover::function(Named_object* fn)
kono
parents:
diff changeset
1047 {
kono
parents:
diff changeset
1048 this->visit(fn);
kono
parents:
diff changeset
1049 return TRAVERSE_CONTINUE;
kono
parents:
diff changeset
1050 }
kono
parents:
diff changeset
1051
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1052 int
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1053 Escape_analysis_discover::function_declaration(Named_object* fn)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1054 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1055 this->visit(fn);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1056 return TRAVERSE_CONTINUE;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1057 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1058
111
kono
parents:
diff changeset
1059 // Visit a function FN, adding it to the current stack of functions
kono
parents:
diff changeset
1060 // in this connected component. If this is the root of the component,
kono
parents:
diff changeset
1061 // create a set of functions to be analyzed later.
kono
parents:
diff changeset
1062 //
kono
parents:
diff changeset
1063 // Finding these sets is finding strongly connected components
kono
parents:
diff changeset
1064 // in the static call graph. The algorithm for doing that is taken
kono
parents:
diff changeset
1065 // from Sedgewick, Algorithms, Second Edition, p. 482, with two
kono
parents:
diff changeset
1066 // adaptations.
kono
parents:
diff changeset
1067 //
kono
parents:
diff changeset
1068 // First, a closure (fn->func_value()->enclosing() == NULL) cannot be the
kono
parents:
diff changeset
1069 // root of a connected component. Refusing to use it as a root
kono
parents:
diff changeset
1070 // forces it into the component of the function in which it appears.
kono
parents:
diff changeset
1071 // This is more convenient for escape analysis.
kono
parents:
diff changeset
1072 //
kono
parents:
diff changeset
1073 // Second, each function becomes two virtual nodes in the graph,
kono
parents:
diff changeset
1074 // with numbers n and n+1. We record the function's node number as n
kono
parents:
diff changeset
1075 // but search from node n+1. If the search tells us that the component
kono
parents:
diff changeset
1076 // number (min) is n+1, we know that this is a trivial component: one function
kono
parents:
diff changeset
1077 // plus its closures. If the search tells us that the component number is
kono
parents:
diff changeset
1078 // n, then there was a path from node n+1 back to node n, meaning that
kono
parents:
diff changeset
1079 // the function set is mutually recursive. The escape analysis can be
kono
parents:
diff changeset
1080 // more precise when analyzing a single non-recursive function than
kono
parents:
diff changeset
1081 // when analyzing a set of mutually recursive functions.
kono
parents:
diff changeset
1082
kono
parents:
diff changeset
1083 int
kono
parents:
diff changeset
1084 Escape_analysis_discover::visit(Named_object* fn)
kono
parents:
diff changeset
1085 {
kono
parents:
diff changeset
1086 Component_ids::const_iterator p = this->component_ids_.find(fn);
kono
parents:
diff changeset
1087 if (p != this->component_ids_.end())
kono
parents:
diff changeset
1088 // Already visited.
kono
parents:
diff changeset
1089 return p->second;
kono
parents:
diff changeset
1090
kono
parents:
diff changeset
1091 this->id++;
kono
parents:
diff changeset
1092 int id = this->id;
kono
parents:
diff changeset
1093 this->component_ids_[fn] = id;
kono
parents:
diff changeset
1094 this->id++;
kono
parents:
diff changeset
1095 int min = this->id;
kono
parents:
diff changeset
1096
kono
parents:
diff changeset
1097 this->stack_.push(fn);
kono
parents:
diff changeset
1098 min = this->visit_code(fn, min);
kono
parents:
diff changeset
1099 if ((min == id || min == id + 1)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1100 && ((fn->is_function() && fn->func_value()->enclosing() == NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1101 || fn->is_function_declaration()))
111
kono
parents:
diff changeset
1102 {
kono
parents:
diff changeset
1103 bool recursive = min == id;
kono
parents:
diff changeset
1104 std::vector<Named_object*> group;
kono
parents:
diff changeset
1105
kono
parents:
diff changeset
1106 for (; !this->stack_.empty(); this->stack_.pop())
kono
parents:
diff changeset
1107 {
kono
parents:
diff changeset
1108 Named_object* n = this->stack_.top();
kono
parents:
diff changeset
1109 if (n == fn)
kono
parents:
diff changeset
1110 {
kono
parents:
diff changeset
1111 this->stack_.pop();
kono
parents:
diff changeset
1112 break;
kono
parents:
diff changeset
1113 }
kono
parents:
diff changeset
1114
kono
parents:
diff changeset
1115 group.push_back(n);
kono
parents:
diff changeset
1116 this->component_ids_[n] = std::numeric_limits<int>::max();
kono
parents:
diff changeset
1117 }
kono
parents:
diff changeset
1118 group.push_back(fn);
kono
parents:
diff changeset
1119 this->component_ids_[fn] = std::numeric_limits<int>::max();
kono
parents:
diff changeset
1120
kono
parents:
diff changeset
1121 std::reverse(group.begin(), group.end());
kono
parents:
diff changeset
1122 this->gogo_->add_analysis_set(group, recursive);
kono
parents:
diff changeset
1123 }
kono
parents:
diff changeset
1124
kono
parents:
diff changeset
1125 return min;
kono
parents:
diff changeset
1126 }
kono
parents:
diff changeset
1127
kono
parents:
diff changeset
1128 // Helper class for discovery step. Traverse expressions looking for
kono
parents:
diff changeset
1129 // function calls and closures to visit during the discovery step.
kono
parents:
diff changeset
1130
kono
parents:
diff changeset
1131 class Escape_discover_expr : public Traverse
kono
parents:
diff changeset
1132 {
kono
parents:
diff changeset
1133 public:
kono
parents:
diff changeset
1134 Escape_discover_expr(Escape_analysis_discover* ead, int min)
kono
parents:
diff changeset
1135 : Traverse(traverse_expressions),
kono
parents:
diff changeset
1136 ead_(ead), min_(min)
kono
parents:
diff changeset
1137 { }
kono
parents:
diff changeset
1138
kono
parents:
diff changeset
1139 int
kono
parents:
diff changeset
1140 min()
kono
parents:
diff changeset
1141 { return this->min_; }
kono
parents:
diff changeset
1142
kono
parents:
diff changeset
1143 int
kono
parents:
diff changeset
1144 expression(Expression** pexpr);
kono
parents:
diff changeset
1145
kono
parents:
diff changeset
1146 private:
kono
parents:
diff changeset
1147 // The original discovery analysis.
kono
parents:
diff changeset
1148 Escape_analysis_discover* ead_;
kono
parents:
diff changeset
1149 // The minimum component ID in this group.
kono
parents:
diff changeset
1150 int min_;
kono
parents:
diff changeset
1151 };
kono
parents:
diff changeset
1152
kono
parents:
diff changeset
1153 // Visit any calls or closures found when discovering expressions.
kono
parents:
diff changeset
1154
kono
parents:
diff changeset
1155 int
kono
parents:
diff changeset
1156 Escape_discover_expr::expression(Expression** pexpr)
kono
parents:
diff changeset
1157 {
kono
parents:
diff changeset
1158 Expression* e = *pexpr;
kono
parents:
diff changeset
1159 Named_object* fn = NULL;
kono
parents:
diff changeset
1160 if (e->call_expression() != NULL
kono
parents:
diff changeset
1161 && e->call_expression()->fn()->func_expression() != NULL)
kono
parents:
diff changeset
1162 {
kono
parents:
diff changeset
1163 // Method call or function call.
kono
parents:
diff changeset
1164 fn = e->call_expression()->fn()->func_expression()->named_object();
kono
parents:
diff changeset
1165 }
kono
parents:
diff changeset
1166 else if (e->func_expression() != NULL
kono
parents:
diff changeset
1167 && e->func_expression()->closure() != NULL)
kono
parents:
diff changeset
1168 {
kono
parents:
diff changeset
1169 // Closure.
kono
parents:
diff changeset
1170 fn = e->func_expression()->named_object();
kono
parents:
diff changeset
1171 }
kono
parents:
diff changeset
1172
kono
parents:
diff changeset
1173 if (fn != NULL)
kono
parents:
diff changeset
1174 this->min_ = std::min(this->min_, this->ead_->visit(fn));
kono
parents:
diff changeset
1175 return TRAVERSE_CONTINUE;
kono
parents:
diff changeset
1176 }
kono
parents:
diff changeset
1177
kono
parents:
diff changeset
1178 // Visit the body of each function, returns ID of the minimum connected
kono
parents:
diff changeset
1179 // component found in the body.
kono
parents:
diff changeset
1180
kono
parents:
diff changeset
1181 int
kono
parents:
diff changeset
1182 Escape_analysis_discover::visit_code(Named_object* fn, int min)
kono
parents:
diff changeset
1183 {
kono
parents:
diff changeset
1184 if (!fn->is_function())
kono
parents:
diff changeset
1185 return min;
kono
parents:
diff changeset
1186
kono
parents:
diff changeset
1187 Escape_discover_expr ede(this, min);
kono
parents:
diff changeset
1188 fn->func_value()->traverse(&ede);
kono
parents:
diff changeset
1189 return ede.min();
kono
parents:
diff changeset
1190 }
kono
parents:
diff changeset
1191
kono
parents:
diff changeset
1192 // Discover strongly connected groups of functions to analyze.
kono
parents:
diff changeset
1193
kono
parents:
diff changeset
1194 void
kono
parents:
diff changeset
1195 Gogo::discover_analysis_sets()
kono
parents:
diff changeset
1196 {
kono
parents:
diff changeset
1197 Escape_analysis_discover ead(this);
kono
parents:
diff changeset
1198 this->traverse(&ead);
kono
parents:
diff changeset
1199 }
kono
parents:
diff changeset
1200
kono
parents:
diff changeset
1201 // Traverse all label and goto statements and mark the underlying label
kono
parents:
diff changeset
1202 // as looping or not looping.
kono
parents:
diff changeset
1203
kono
parents:
diff changeset
1204 class Escape_analysis_loop : public Traverse
kono
parents:
diff changeset
1205 {
kono
parents:
diff changeset
1206 public:
kono
parents:
diff changeset
1207 Escape_analysis_loop()
kono
parents:
diff changeset
1208 : Traverse(traverse_statements)
kono
parents:
diff changeset
1209 { }
kono
parents:
diff changeset
1210
kono
parents:
diff changeset
1211 int
kono
parents:
diff changeset
1212 statement(Block*, size_t*, Statement*);
kono
parents:
diff changeset
1213 };
kono
parents:
diff changeset
1214
kono
parents:
diff changeset
1215 int
kono
parents:
diff changeset
1216 Escape_analysis_loop::statement(Block*, size_t*, Statement* s)
kono
parents:
diff changeset
1217 {
kono
parents:
diff changeset
1218 if (s->label_statement() != NULL)
kono
parents:
diff changeset
1219 s->label_statement()->label()->set_nonlooping();
kono
parents:
diff changeset
1220 else if (s->goto_statement() != NULL)
kono
parents:
diff changeset
1221 {
kono
parents:
diff changeset
1222 if (s->goto_statement()->label()->nonlooping())
kono
parents:
diff changeset
1223 s->goto_statement()->label()->set_looping();
kono
parents:
diff changeset
1224 }
kono
parents:
diff changeset
1225 return TRAVERSE_CONTINUE;
kono
parents:
diff changeset
1226 }
kono
parents:
diff changeset
1227
kono
parents:
diff changeset
1228 // Traversal class used to look at all interesting statements within a function
kono
parents:
diff changeset
1229 // in order to build a connectivity graph between all nodes within a context's
kono
parents:
diff changeset
1230 // scope.
kono
parents:
diff changeset
1231
kono
parents:
diff changeset
1232 class Escape_analysis_assign : public Traverse
kono
parents:
diff changeset
1233 {
kono
parents:
diff changeset
1234 public:
kono
parents:
diff changeset
1235 Escape_analysis_assign(Escape_context* context, Named_object* fn)
kono
parents:
diff changeset
1236 : Traverse(traverse_statements
kono
parents:
diff changeset
1237 | traverse_expressions),
kono
parents:
diff changeset
1238 context_(context), fn_(fn)
kono
parents:
diff changeset
1239 { }
kono
parents:
diff changeset
1240
kono
parents:
diff changeset
1241 // Model statements within a function as assignments and flows between nodes.
kono
parents:
diff changeset
1242 int
kono
parents:
diff changeset
1243 statement(Block*, size_t*, Statement*);
kono
parents:
diff changeset
1244
kono
parents:
diff changeset
1245 // Model expressions within a function as assignments and flows between nodes.
kono
parents:
diff changeset
1246 int
kono
parents:
diff changeset
1247 expression(Expression**);
kono
parents:
diff changeset
1248
kono
parents:
diff changeset
1249 // Model calls within a function as assignments and flows between arguments
kono
parents:
diff changeset
1250 // and results.
kono
parents:
diff changeset
1251 void
kono
parents:
diff changeset
1252 call(Call_expression* call);
kono
parents:
diff changeset
1253
kono
parents:
diff changeset
1254 // Model the assignment of DST to SRC.
kono
parents:
diff changeset
1255 void
kono
parents:
diff changeset
1256 assign(Node* dst, Node* src);
kono
parents:
diff changeset
1257
kono
parents:
diff changeset
1258 // Model the assignment of DST to dereference of SRC.
kono
parents:
diff changeset
1259 void
kono
parents:
diff changeset
1260 assign_deref(Node* dst, Node* src);
kono
parents:
diff changeset
1261
kono
parents:
diff changeset
1262 // Model the input-to-output assignment flow of one of a function call's
kono
parents:
diff changeset
1263 // arguments, where the flow is encoding in NOTE.
kono
parents:
diff changeset
1264 int
kono
parents:
diff changeset
1265 assign_from_note(std::string* note, const std::vector<Node*>& dsts,
kono
parents:
diff changeset
1266 Node* src);
kono
parents:
diff changeset
1267
kono
parents:
diff changeset
1268 // Record the flow of SRC to DST in DST.
kono
parents:
diff changeset
1269 void
kono
parents:
diff changeset
1270 flows(Node* dst, Node* src);
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 private:
kono
parents:
diff changeset
1273 // The escape context for this set of functions.
kono
parents:
diff changeset
1274 Escape_context* context_;
kono
parents:
diff changeset
1275 // The current function being analyzed.
kono
parents:
diff changeset
1276 Named_object* fn_;
kono
parents:
diff changeset
1277 };
kono
parents:
diff changeset
1278
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1279 // Helper function to detect self assignment like the following.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1280 //
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1281 // func (b *Buffer) Foo() {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1282 // n, m := ...
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1283 // b.buf = b.buf[n:m]
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1284 // }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1285
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1286 static bool
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1287 is_self_assignment(Expression* lhs, Expression* rhs)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1288 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1289 Unary_expression* lue =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1290 (lhs->field_reference_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1291 ? lhs->field_reference_expression()->expr()->unary_expression()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1292 : lhs->unary_expression());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1293 Var_expression* lve =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1294 (lue != NULL && lue->op() == OPERATOR_MULT ? lue->operand()->var_expression() : NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1295 Array_index_expression* raie = rhs->array_index_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1296 String_index_expression* rsie = rhs->string_index_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1297 Expression* rarray =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1298 (raie != NULL && raie->end() != NULL && raie->array()->type()->is_slice_type()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1299 ? raie->array()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1300 : (rsie != NULL && rsie->type()->is_string_type() ? rsie->string() : NULL));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1301 Unary_expression* rue =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1302 (rarray != NULL && rarray->field_reference_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1303 ? rarray->field_reference_expression()->expr()->unary_expression()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1304 : (rarray != NULL ? rarray->unary_expression() : NULL));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1305 Var_expression* rve =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1306 (rue != NULL && rue->op() == OPERATOR_MULT ? rue->operand()->var_expression() : NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1307 return lve != NULL && rve != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1308 && lve->named_object() == rve->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1309 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1310
111
kono
parents:
diff changeset
1311 // Model statements within a function as assignments and flows between nodes.
kono
parents:
diff changeset
1312
kono
parents:
diff changeset
1313 int
kono
parents:
diff changeset
1314 Escape_analysis_assign::statement(Block*, size_t*, Statement* s)
kono
parents:
diff changeset
1315 {
kono
parents:
diff changeset
1316 // Adjust the loop depth as we enter/exit blocks related to for statements.
kono
parents:
diff changeset
1317 bool is_for_statement = (s->is_block_statement()
kono
parents:
diff changeset
1318 && s->block_statement()->is_lowered_for_statement());
kono
parents:
diff changeset
1319 if (is_for_statement)
kono
parents:
diff changeset
1320 this->context_->increase_loop_depth();
kono
parents:
diff changeset
1321
kono
parents:
diff changeset
1322 s->traverse_contents(this);
kono
parents:
diff changeset
1323
kono
parents:
diff changeset
1324 if (is_for_statement)
kono
parents:
diff changeset
1325 this->context_->decrease_loop_depth();
kono
parents:
diff changeset
1326
kono
parents:
diff changeset
1327 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
1328 int debug_level = gogo->debug_escape_level();
kono
parents:
diff changeset
1329 if (debug_level > 1
kono
parents:
diff changeset
1330 && s->unnamed_label_statement() == NULL
kono
parents:
diff changeset
1331 && s->expression_statement() == NULL
kono
parents:
diff changeset
1332 && !s->is_block_statement())
kono
parents:
diff changeset
1333 {
kono
parents:
diff changeset
1334 Node* n = Node::make_node(s);
kono
parents:
diff changeset
1335 std::string fn_name = this->context_->current_function_name();
kono
parents:
diff changeset
1336 go_inform(s->location(), "[%d] %s esc: %s",
kono
parents:
diff changeset
1337 this->context_->loop_depth(), fn_name.c_str(),
kono
parents:
diff changeset
1338 n->ast_format(gogo).c_str());
kono
parents:
diff changeset
1339 }
kono
parents:
diff changeset
1340
kono
parents:
diff changeset
1341 switch (s->classification())
kono
parents:
diff changeset
1342 {
kono
parents:
diff changeset
1343 case Statement::STATEMENT_VARIABLE_DECLARATION:
kono
parents:
diff changeset
1344 {
kono
parents:
diff changeset
1345 Named_object* var = s->variable_declaration_statement()->var();
kono
parents:
diff changeset
1346 Node* var_node = Node::make_node(var);
kono
parents:
diff changeset
1347 Node::Escape_state* state = var_node->state(this->context_, NULL);
kono
parents:
diff changeset
1348 state->loop_depth = this->context_->loop_depth();
kono
parents:
diff changeset
1349
kono
parents:
diff changeset
1350 // Set the loop depth for this declaration.
kono
parents:
diff changeset
1351 if (var->is_variable()
kono
parents:
diff changeset
1352 && var->var_value()->init() != NULL)
kono
parents:
diff changeset
1353 {
kono
parents:
diff changeset
1354 Node* init_node = Node::make_node(var->var_value()->init());
kono
parents:
diff changeset
1355 this->assign(var_node, init_node);
kono
parents:
diff changeset
1356 }
kono
parents:
diff changeset
1357 }
kono
parents:
diff changeset
1358 break;
kono
parents:
diff changeset
1359
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1360 case Statement::STATEMENT_TEMPORARY:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1361 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1362 Expression* init = s->temporary_statement()->init();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1363 if (init != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1364 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1365 Node* n = Node::make_node(init);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1366 if (s->temporary_statement()->value_escapes())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1367 this->assign(this->context_->sink(), n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1368 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1369 this->assign(Node::make_node(s), n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1370 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1371 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1372 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1373
111
kono
parents:
diff changeset
1374 case Statement::STATEMENT_LABEL:
kono
parents:
diff changeset
1375 {
kono
parents:
diff changeset
1376 Label_statement* label_stmt = s->label_statement();
kono
parents:
diff changeset
1377 if (label_stmt->label()->looping())
kono
parents:
diff changeset
1378 this->context_->increase_loop_depth();
kono
parents:
diff changeset
1379
kono
parents:
diff changeset
1380 if (debug_level > 1)
kono
parents:
diff changeset
1381 {
kono
parents:
diff changeset
1382 std::string label_type = (label_stmt->label()->looping()
kono
parents:
diff changeset
1383 ? "looping"
kono
parents:
diff changeset
1384 : "nonlooping");
kono
parents:
diff changeset
1385 go_inform(s->location(), "%s %s label",
kono
parents:
diff changeset
1386 label_stmt->label()->name().c_str(),
kono
parents:
diff changeset
1387 label_type.c_str());
kono
parents:
diff changeset
1388 }
kono
parents:
diff changeset
1389 }
kono
parents:
diff changeset
1390 break;
kono
parents:
diff changeset
1391
kono
parents:
diff changeset
1392 case Statement::STATEMENT_SWITCH:
kono
parents:
diff changeset
1393 case Statement::STATEMENT_TYPE_SWITCH:
kono
parents:
diff changeset
1394 // Want to model the assignment of each case variable to the switched upon
kono
parents:
diff changeset
1395 // variable. This should be lowered into assignment statements; nothing
kono
parents:
diff changeset
1396 // to here if that's the case.
kono
parents:
diff changeset
1397 break;
kono
parents:
diff changeset
1398
kono
parents:
diff changeset
1399 case Statement::STATEMENT_ASSIGNMENT:
kono
parents:
diff changeset
1400 {
kono
parents:
diff changeset
1401 Assignment_statement* assn = s->assignment_statement();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1402 Expression* lhs = assn->lhs();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1403 Expression* rhs = assn->rhs();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1404 Node* lhs_node = Node::make_node(lhs);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1405 Node* rhs_node = Node::make_node(rhs);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1406
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1407 // Filter out the following special case.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1408 //
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1409 // func (b *Buffer) Foo() {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1410 // n, m := ...
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1411 // b.buf = b.buf[n:m]
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1412 // }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1413 //
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1414 // This assignment is a no-op for escape analysis,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1415 // it does not store any new pointers into b that were not already there.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1416 // However, without this special case b will escape.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1417 if (is_self_assignment(lhs, rhs))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1418 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1419 if (debug_level != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1420 go_inform(s->location(), "%s ignoring self-assignment to %s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1421 strip_packed_prefix(gogo, this->context_->current_function_name()).c_str(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1422 lhs_node->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1423 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1424 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1425
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1426 this->assign(lhs_node, rhs_node);
111
kono
parents:
diff changeset
1427 }
kono
parents:
diff changeset
1428 break;
kono
parents:
diff changeset
1429
kono
parents:
diff changeset
1430 case Statement::STATEMENT_SEND:
kono
parents:
diff changeset
1431 {
kono
parents:
diff changeset
1432 Node* sent_node = Node::make_node(s->send_statement()->val());
kono
parents:
diff changeset
1433 this->assign(this->context_->sink(), sent_node);
kono
parents:
diff changeset
1434 }
kono
parents:
diff changeset
1435 break;
kono
parents:
diff changeset
1436
kono
parents:
diff changeset
1437 case Statement::STATEMENT_DEFER:
kono
parents:
diff changeset
1438 if (this->context_->loop_depth() == 1)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1439 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1440 // Defer statement may need to allocate a thunk. When it is
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1441 // not inside a loop, this can be stack allocated, as it
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1442 // runs before the function finishes.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1443 Node* n = Node::make_node(s);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1444 n->set_encoding(Node::ESCAPE_NONE);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1445 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1446 }
111
kono
parents:
diff changeset
1447 // fallthrough
kono
parents:
diff changeset
1448
kono
parents:
diff changeset
1449 case Statement::STATEMENT_GO:
kono
parents:
diff changeset
1450 {
kono
parents:
diff changeset
1451 // Defer f(x) or go f(x).
kono
parents:
diff changeset
1452 // Both f and x escape to the heap.
kono
parents:
diff changeset
1453 Thunk_statement* thunk = s->thunk_statement();
kono
parents:
diff changeset
1454 if (thunk->call()->call_expression() == NULL)
kono
parents:
diff changeset
1455 break;
kono
parents:
diff changeset
1456
kono
parents:
diff changeset
1457 Call_expression* call = thunk->call()->call_expression();
kono
parents:
diff changeset
1458 Node* func_node = Node::make_node(call->fn());
kono
parents:
diff changeset
1459 this->assign(this->context_->sink(), func_node);
kono
parents:
diff changeset
1460 if (call->args() != NULL)
kono
parents:
diff changeset
1461 {
kono
parents:
diff changeset
1462 for (Expression_list::const_iterator p = call->args()->begin();
kono
parents:
diff changeset
1463 p != call->args()->end();
kono
parents:
diff changeset
1464 ++p)
kono
parents:
diff changeset
1465 {
kono
parents:
diff changeset
1466 Node* arg_node = Node::make_node(*p);
kono
parents:
diff changeset
1467 this->assign(this->context_->sink(), arg_node);
kono
parents:
diff changeset
1468 }
kono
parents:
diff changeset
1469 }
kono
parents:
diff changeset
1470 }
kono
parents:
diff changeset
1471 break;
kono
parents:
diff changeset
1472
kono
parents:
diff changeset
1473 default:
kono
parents:
diff changeset
1474 break;
kono
parents:
diff changeset
1475 }
kono
parents:
diff changeset
1476 return TRAVERSE_SKIP_COMPONENTS;
kono
parents:
diff changeset
1477 }
kono
parents:
diff changeset
1478
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1479 // Helper function to emit moved-to-heap diagnostics.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1480
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1481 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1482 move_to_heap(Gogo* gogo, Expression *expr)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1483 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1484 Named_object* no;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1485 if (expr->var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1486 no = expr->var_expression()->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1487 else if (expr->enclosed_var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1488 no = expr->enclosed_var_expression()->variable();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1489 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1490 return;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1491
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1492 if ((no->is_variable()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1493 && !no->var_value()->is_global())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1494 || no->is_result_variable())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1495 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1496 Node* n = Node::make_node(expr);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1497 if (gogo->debug_escape_level() != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1498 go_inform(n->definition_location(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1499 "moved to heap: %s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1500 n->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1501 if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1502 go_error_at(expr->location(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1503 "%s escapes to heap, not allowed in runtime",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1504 n->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1505 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1506 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1507
111
kono
parents:
diff changeset
1508 // Model expressions within a function as assignments and flows between nodes.
kono
parents:
diff changeset
1509
kono
parents:
diff changeset
1510 int
kono
parents:
diff changeset
1511 Escape_analysis_assign::expression(Expression** pexpr)
kono
parents:
diff changeset
1512 {
kono
parents:
diff changeset
1513 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
1514 int debug_level = gogo->debug_escape_level();
kono
parents:
diff changeset
1515
kono
parents:
diff changeset
1516 // Big stuff escapes unconditionally.
kono
parents:
diff changeset
1517 Node* n = Node::make_node(*pexpr);
kono
parents:
diff changeset
1518 if ((n->encoding() & ESCAPE_MASK) != int(Node::ESCAPE_HEAP)
kono
parents:
diff changeset
1519 && n->is_big(this->context_))
kono
parents:
diff changeset
1520 {
kono
parents:
diff changeset
1521 if (debug_level > 1)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1522 go_inform((*pexpr)->location(), "%s too large for stack",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1523 n->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1524 move_to_heap(gogo, *pexpr);
111
kono
parents:
diff changeset
1525 n->set_encoding(Node::ESCAPE_HEAP);
kono
parents:
diff changeset
1526 (*pexpr)->address_taken(true);
kono
parents:
diff changeset
1527 this->assign(this->context_->sink(), n);
kono
parents:
diff changeset
1528 }
kono
parents:
diff changeset
1529
kono
parents:
diff changeset
1530 if ((*pexpr)->func_expression() == NULL)
kono
parents:
diff changeset
1531 (*pexpr)->traverse_subexpressions(this);
kono
parents:
diff changeset
1532
kono
parents:
diff changeset
1533 if (debug_level > 1)
kono
parents:
diff changeset
1534 {
kono
parents:
diff changeset
1535 Node* n = Node::make_node(*pexpr);
kono
parents:
diff changeset
1536 std::string fn_name = this->context_->current_function_name();
kono
parents:
diff changeset
1537 go_inform((*pexpr)->location(), "[%d] %s esc: %s",
kono
parents:
diff changeset
1538 this->context_->loop_depth(), fn_name.c_str(),
kono
parents:
diff changeset
1539 n->ast_format(gogo).c_str());
kono
parents:
diff changeset
1540 }
kono
parents:
diff changeset
1541
kono
parents:
diff changeset
1542 switch ((*pexpr)->classification())
kono
parents:
diff changeset
1543 {
kono
parents:
diff changeset
1544 case Expression::EXPRESSION_CALL:
kono
parents:
diff changeset
1545 {
kono
parents:
diff changeset
1546 Call_expression* call = (*pexpr)->call_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1547 if (call->is_builtin())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1548 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1549 Builtin_call_expression* bce = call->builtin_call_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1550 switch (bce->code())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1551 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1552 case Builtin_call_expression::BUILTIN_PANIC:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1553 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1554 // Argument could leak through recover.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1555 Node* panic_arg = Node::make_node(call->args()->front());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1556 this->assign(this->context_->sink(), panic_arg);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1557 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1558 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1559
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1560 case Builtin_call_expression::BUILTIN_APPEND:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1561 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1562 // The contents being appended leak.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1563 if (call->is_varargs())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1564 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1565 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1566 Node* appended = Node::make_node(call->args()->back());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1567 this->assign_deref(this->context_->sink(), appended);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1568 if (debug_level > 2)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1569 go_inform((*pexpr)->location(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1570 "special treatment of append(slice1, slice2...)");
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1571 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1572 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1573 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1574 for (Expression_list::const_iterator pa =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1575 call->args()->begin() + 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1576 pa != call->args()->end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1577 ++pa)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1578 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1579 Node* arg = Node::make_node(*pa);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1580 this->assign(this->context_->sink(), arg);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1581 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1582 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1583
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1584 // The content of the original slice leaks as well.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1585 Node* appendee = Node::make_node(call->args()->front());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1586 this->assign_deref(this->context_->sink(), appendee);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1587 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1588 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1589
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1590 case Builtin_call_expression::BUILTIN_COPY:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1591 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1592 // Lose track of the copied content.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1593 Node* copied = Node::make_node(call->args()->back());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1594 this->assign_deref(this->context_->sink(), copied);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1595 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1596 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1597
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1598 default:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1599 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1600 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1601 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1602 }
111
kono
parents:
diff changeset
1603 Func_expression* fe = call->fn()->func_expression();
kono
parents:
diff changeset
1604 if (fe != NULL && fe->is_runtime_function())
kono
parents:
diff changeset
1605 {
kono
parents:
diff changeset
1606 switch (fe->runtime_code())
kono
parents:
diff changeset
1607 {
kono
parents:
diff changeset
1608 case Runtime::MAKECHAN:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1609 case Runtime::MAKECHAN64:
111
kono
parents:
diff changeset
1610 case Runtime::MAKEMAP:
kono
parents:
diff changeset
1611 case Runtime::MAKESLICE:
kono
parents:
diff changeset
1612 case Runtime::MAKESLICE64:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1613 this->context_->track(n);
111
kono
parents:
diff changeset
1614 break;
kono
parents:
diff changeset
1615
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1616 case Runtime::MAPASSIGN:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1617 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1618 // Map key escapes. The last argument is the address
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1619 // of the key.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1620 Node* key_node = Node::make_node(call->args()->back());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1621 this->assign_deref(this->context_->sink(), key_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1622 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1623 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1624
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1625 case Runtime::IFACEE2T2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1626 case Runtime::IFACEI2T2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1627 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1628 // x, ok = v.(T), where T is non-pointer non-interface,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1629 // is lowered to
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1630 // ok = IFACEI2T2(type, v, (void*)&tmp_x)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1631 // Here v flows to tmp_x.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1632 // Note: other IFACEX2Y2 returns the conversion result.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1633 // Those are handled in ::assign.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1634 Node* src_node = Node::make_node(call->args()->at(1));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1635 Node* dst_node;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1636 Expression* arg2 = call->args()->at(2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1637 // Try to pull tmp_x out of the arg2 expression, and let v
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1638 // flows into it, instead of simply dereference arg2,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1639 // which looks like dereference of an arbitrary pointer
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1640 // and causes v immediately escape.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1641 // The expression form matches statement.cc,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1642 // Tuple_type_guard_assignment_statement::lower_to_object_type.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1643 Unary_expression* ue =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1644 (arg2->conversion_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1645 ? arg2->conversion_expression()->expr()->unary_expression()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1646 : arg2->unary_expression());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1647 if (ue != NULL && ue->op() == OPERATOR_AND)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1648 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1649 if (!ue->operand()->type()->has_pointer())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1650 // Don't bother flowing non-pointer.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1651 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1652 dst_node = Node::make_node(ue->operand());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1653 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1654 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1655 dst_node = this->context_->add_dereference(Node::make_node(arg2));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1656 this->assign(dst_node, src_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1657 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1658 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1659
111
kono
parents:
diff changeset
1660 default:
kono
parents:
diff changeset
1661 break;
kono
parents:
diff changeset
1662 }
kono
parents:
diff changeset
1663 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1664 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1665 this->call(call);
111
kono
parents:
diff changeset
1666 }
kono
parents:
diff changeset
1667 break;
kono
parents:
diff changeset
1668
kono
parents:
diff changeset
1669 case Expression::EXPRESSION_ALLOCATION:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1670 // This is Runtime::NEW.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1671 this->context_->track(n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1672 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1673
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1674 case Expression::EXPRESSION_STRING_CONCAT:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1675 this->context_->track(n);
111
kono
parents:
diff changeset
1676 break;
kono
parents:
diff changeset
1677
kono
parents:
diff changeset
1678 case Expression::EXPRESSION_CONVERSION:
kono
parents:
diff changeset
1679 {
kono
parents:
diff changeset
1680 Type_conversion_expression* tce = (*pexpr)->conversion_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1681 Type* ft = tce->expr()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1682 Type* tt = tce->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1683 if ((ft->is_string_type() && tt->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1684 || (ft->is_slice_type() && tt->is_string_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1685 || (ft->integer_type() != NULL && tt->is_string_type()))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1686 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1687 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1688 this->context_->track(n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1689 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1690 }
111
kono
parents:
diff changeset
1691 Node* tce_node = Node::make_node(tce);
kono
parents:
diff changeset
1692 Node* converted = Node::make_node(tce->expr());
kono
parents:
diff changeset
1693 this->context_->track(tce_node);
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 this->assign(tce_node, converted);
kono
parents:
diff changeset
1696 }
kono
parents:
diff changeset
1697 break;
kono
parents:
diff changeset
1698
kono
parents:
diff changeset
1699 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
kono
parents:
diff changeset
1700 case Expression::EXPRESSION_SLICE_CONSTRUCTION:
kono
parents:
diff changeset
1701 {
kono
parents:
diff changeset
1702 Node* array_node = Node::make_node(*pexpr);
kono
parents:
diff changeset
1703 if ((*pexpr)->slice_literal() != NULL)
kono
parents:
diff changeset
1704 this->context_->track(array_node);
kono
parents:
diff changeset
1705
kono
parents:
diff changeset
1706 Expression_list* vals = ((*pexpr)->slice_literal() != NULL
kono
parents:
diff changeset
1707 ? (*pexpr)->slice_literal()->vals()
kono
parents:
diff changeset
1708 : (*pexpr)->array_literal()->vals());
kono
parents:
diff changeset
1709
kono
parents:
diff changeset
1710 if (vals != NULL)
kono
parents:
diff changeset
1711 {
kono
parents:
diff changeset
1712 // Connect the array to its values.
kono
parents:
diff changeset
1713 for (Expression_list::const_iterator p = vals->begin();
kono
parents:
diff changeset
1714 p != vals->end();
kono
parents:
diff changeset
1715 ++p)
kono
parents:
diff changeset
1716 if ((*p) != NULL)
kono
parents:
diff changeset
1717 this->assign(array_node, Node::make_node(*p));
kono
parents:
diff changeset
1718 }
kono
parents:
diff changeset
1719 }
kono
parents:
diff changeset
1720 break;
kono
parents:
diff changeset
1721
kono
parents:
diff changeset
1722 case Expression::EXPRESSION_STRUCT_CONSTRUCTION:
kono
parents:
diff changeset
1723 {
kono
parents:
diff changeset
1724 Node* struct_node = Node::make_node(*pexpr);
kono
parents:
diff changeset
1725 Expression_list* vals = (*pexpr)->struct_literal()->vals();
kono
parents:
diff changeset
1726 if (vals != NULL)
kono
parents:
diff changeset
1727 {
kono
parents:
diff changeset
1728 // Connect the struct to its values.
kono
parents:
diff changeset
1729 for (Expression_list::const_iterator p = vals->begin();
kono
parents:
diff changeset
1730 p != vals->end();
kono
parents:
diff changeset
1731 ++p)
kono
parents:
diff changeset
1732 {
kono
parents:
diff changeset
1733 if ((*p) != NULL)
kono
parents:
diff changeset
1734 this->assign(struct_node, Node::make_node(*p));
kono
parents:
diff changeset
1735 }
kono
parents:
diff changeset
1736 }
kono
parents:
diff changeset
1737 }
kono
parents:
diff changeset
1738 break;
kono
parents:
diff changeset
1739
kono
parents:
diff changeset
1740 case Expression::EXPRESSION_HEAP:
kono
parents:
diff changeset
1741 {
kono
parents:
diff changeset
1742 Node* pointer_node = Node::make_node(*pexpr);
kono
parents:
diff changeset
1743 Node* lit_node = Node::make_node((*pexpr)->heap_expression()->expr());
kono
parents:
diff changeset
1744 this->context_->track(pointer_node);
kono
parents:
diff changeset
1745
kono
parents:
diff changeset
1746 // Connect pointer node to literal node; if the pointer node escapes, so
kono
parents:
diff changeset
1747 // does the literal node.
kono
parents:
diff changeset
1748 this->assign(pointer_node, lit_node);
kono
parents:
diff changeset
1749 }
kono
parents:
diff changeset
1750 break;
kono
parents:
diff changeset
1751
kono
parents:
diff changeset
1752 case Expression::EXPRESSION_BOUND_METHOD:
kono
parents:
diff changeset
1753 {
kono
parents:
diff changeset
1754 Node* bound_node = Node::make_node(*pexpr);
kono
parents:
diff changeset
1755 this->context_->track(bound_node);
kono
parents:
diff changeset
1756
kono
parents:
diff changeset
1757 Expression* obj = (*pexpr)->bound_method_expression()->first_argument();
kono
parents:
diff changeset
1758 Node* obj_node = Node::make_node(obj);
kono
parents:
diff changeset
1759
kono
parents:
diff changeset
1760 // A bound method implies the receiver will be used outside of the
kono
parents:
diff changeset
1761 // lifetime of the method in some way. We lose track of the receiver.
kono
parents:
diff changeset
1762 this->assign(this->context_->sink(), obj_node);
kono
parents:
diff changeset
1763 }
kono
parents:
diff changeset
1764 break;
kono
parents:
diff changeset
1765
kono
parents:
diff changeset
1766 case Expression::EXPRESSION_MAP_CONSTRUCTION:
kono
parents:
diff changeset
1767 {
kono
parents:
diff changeset
1768 Map_construction_expression* mce = (*pexpr)->map_literal();
kono
parents:
diff changeset
1769 Node* map_node = Node::make_node(mce);
kono
parents:
diff changeset
1770 this->context_->track(map_node);
kono
parents:
diff changeset
1771
kono
parents:
diff changeset
1772 // All keys and values escape to memory.
kono
parents:
diff changeset
1773 if (mce->vals() != NULL)
kono
parents:
diff changeset
1774 {
kono
parents:
diff changeset
1775 for (Expression_list::const_iterator p = mce->vals()->begin();
kono
parents:
diff changeset
1776 p != mce->vals()->end();
kono
parents:
diff changeset
1777 ++p)
kono
parents:
diff changeset
1778 {
kono
parents:
diff changeset
1779 if ((*p) != NULL)
kono
parents:
diff changeset
1780 this->assign(this->context_->sink(), Node::make_node(*p));
kono
parents:
diff changeset
1781 }
kono
parents:
diff changeset
1782 }
kono
parents:
diff changeset
1783 }
kono
parents:
diff changeset
1784 break;
kono
parents:
diff changeset
1785
kono
parents:
diff changeset
1786 case Expression::EXPRESSION_FUNC_REFERENCE:
kono
parents:
diff changeset
1787 {
kono
parents:
diff changeset
1788 Func_expression* fe = (*pexpr)->func_expression();
kono
parents:
diff changeset
1789 if (fe->closure() != NULL)
kono
parents:
diff changeset
1790 {
kono
parents:
diff changeset
1791 // Connect captured variables to the closure.
kono
parents:
diff changeset
1792 Node* closure_node = Node::make_node(fe);
kono
parents:
diff changeset
1793 this->context_->track(closure_node);
kono
parents:
diff changeset
1794
kono
parents:
diff changeset
1795 // A closure expression already exists as the heap expression:
kono
parents:
diff changeset
1796 // &struct{f func_code, v []*Variable}{...}.
kono
parents:
diff changeset
1797 // Link closure to the addresses of the variables enclosed.
kono
parents:
diff changeset
1798 Heap_expression* he = fe->closure()->heap_expression();
kono
parents:
diff changeset
1799 Struct_construction_expression* sce = he->expr()->struct_literal();
kono
parents:
diff changeset
1800
kono
parents:
diff changeset
1801 // First field is function code, other fields are variable
kono
parents:
diff changeset
1802 // references.
kono
parents:
diff changeset
1803 Expression_list::const_iterator p = sce->vals()->begin();
kono
parents:
diff changeset
1804 ++p;
kono
parents:
diff changeset
1805 for (; p != sce->vals()->end(); ++p)
kono
parents:
diff changeset
1806 {
kono
parents:
diff changeset
1807 Node* enclosed_node = Node::make_node(*p);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1808 this->context_->track(enclosed_node);
111
kono
parents:
diff changeset
1809 this->assign(closure_node, enclosed_node);
kono
parents:
diff changeset
1810 }
kono
parents:
diff changeset
1811 }
kono
parents:
diff changeset
1812 }
kono
parents:
diff changeset
1813 break;
kono
parents:
diff changeset
1814
kono
parents:
diff changeset
1815 case Expression::EXPRESSION_UNARY:
kono
parents:
diff changeset
1816 {
kono
parents:
diff changeset
1817 Expression* operand = (*pexpr)->unary_expression()->operand();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1818
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1819 if ((*pexpr)->unary_expression()->op() == OPERATOR_AND)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1820 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1821 this->context_->track(n);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1822
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1823 Named_object* var = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1824 if (operand->var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1825 var = operand->var_expression()->named_object();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1826 else if (operand->enclosed_var_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1827 var = operand->enclosed_var_expression()->variable();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1828
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1829 if (var != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1830 && ((var->is_variable() && var->var_value()->is_parameter())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1831 || var->is_result_variable()))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1832 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1833 Node::Escape_state* addr_state = n->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1834 addr_state->loop_depth = 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1835 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1836 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1837 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1838
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1839 if ((*pexpr)->unary_expression()->op() != OPERATOR_AND
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1840 && (*pexpr)->unary_expression()->op() != OPERATOR_MULT)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1841 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1842
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1843 // For &x and *x, use the loop depth of x if known.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1844 Node::Escape_state* expr_state = n->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1845 Node* operand_node = Node::make_node(operand);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1846 Node::Escape_state* operand_state = operand_node->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1847 if (operand_state->loop_depth != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1848 expr_state->loop_depth = operand_state->loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1849 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1850 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1851
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1852 case Expression::EXPRESSION_ARRAY_INDEX:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1853 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1854 Array_index_expression* aie = (*pexpr)->array_index_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1855
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1856 // Propagate the loopdepth to element.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1857 Node* array_node = Node::make_node(aie->array());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1858 Node::Escape_state* elem_state = n->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1859 Node::Escape_state* array_state = array_node->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1860 elem_state->loop_depth = array_state->loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1861
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1862 if (aie->end() != NULL && !aie->array()->type()->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1863 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1864 // Slicing an array. This effectively takes the address of the array.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1865 Expression* addr = Expression::make_unary(OPERATOR_AND, aie->array(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1866 aie->location());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1867 Node* addr_node = Node::make_node(addr);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1868 n->set_child(addr_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1869 this->context_->track(addr_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1870
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1871 Node::Escape_state* addr_state = addr_node->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1872 addr_state->loop_depth = array_state->loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1873 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1874 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1875 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1876
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1877 case Expression::EXPRESSION_FIELD_REFERENCE:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1878 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1879 // Propagate the loopdepth to field.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1880 Node* struct_node =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1881 Node::make_node((*pexpr)->field_reference_expression()->expr());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1882 Node::Escape_state* field_state = n->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1883 Node::Escape_state* struct_state = struct_node->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1884 field_state->loop_depth = struct_state->loop_depth;
111
kono
parents:
diff changeset
1885 }
kono
parents:
diff changeset
1886 break;
kono
parents:
diff changeset
1887
kono
parents:
diff changeset
1888 default:
kono
parents:
diff changeset
1889 break;
kono
parents:
diff changeset
1890 }
kono
parents:
diff changeset
1891 return TRAVERSE_SKIP_COMPONENTS;
kono
parents:
diff changeset
1892 }
kono
parents:
diff changeset
1893
kono
parents:
diff changeset
1894 // Model calls within a function as assignments and flows between arguments
kono
parents:
diff changeset
1895 // and results.
kono
parents:
diff changeset
1896
kono
parents:
diff changeset
1897 void
kono
parents:
diff changeset
1898 Escape_analysis_assign::call(Call_expression* call)
kono
parents:
diff changeset
1899 {
kono
parents:
diff changeset
1900 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
1901 int debug_level = gogo->debug_escape_level();
kono
parents:
diff changeset
1902
kono
parents:
diff changeset
1903 Func_expression* fn = call->fn()->func_expression();
kono
parents:
diff changeset
1904 Function_type* fntype = call->get_function_type();
kono
parents:
diff changeset
1905 bool indirect = false;
kono
parents:
diff changeset
1906
kono
parents:
diff changeset
1907 // Interface method calls or closure calls are indirect calls.
kono
parents:
diff changeset
1908 if (fntype == NULL
kono
parents:
diff changeset
1909 || (fntype->is_method()
kono
parents:
diff changeset
1910 && fntype->receiver()->type()->interface_type() != NULL)
kono
parents:
diff changeset
1911 || fn == NULL
kono
parents:
diff changeset
1912 || (fn->named_object()->is_function()
kono
parents:
diff changeset
1913 && fn->named_object()->func_value()->enclosing() != NULL))
kono
parents:
diff changeset
1914 indirect = true;
kono
parents:
diff changeset
1915
kono
parents:
diff changeset
1916 Node* call_node = Node::make_node(call);
kono
parents:
diff changeset
1917 std::vector<Node*> arg_nodes;
kono
parents:
diff changeset
1918 if (call->fn()->interface_field_reference_expression() != NULL)
kono
parents:
diff changeset
1919 {
kono
parents:
diff changeset
1920 Interface_field_reference_expression* ifre =
kono
parents:
diff changeset
1921 call->fn()->interface_field_reference_expression();
kono
parents:
diff changeset
1922 Node* field_node = Node::make_node(ifre->expr());
kono
parents:
diff changeset
1923 arg_nodes.push_back(field_node);
kono
parents:
diff changeset
1924 }
kono
parents:
diff changeset
1925
kono
parents:
diff changeset
1926 if (call->args() != NULL)
kono
parents:
diff changeset
1927 {
kono
parents:
diff changeset
1928 for (Expression_list::const_iterator p = call->args()->begin();
kono
parents:
diff changeset
1929 p != call->args()->end();
kono
parents:
diff changeset
1930 ++p)
kono
parents:
diff changeset
1931 arg_nodes.push_back(Node::make_node(*p));
kono
parents:
diff changeset
1932 }
kono
parents:
diff changeset
1933
kono
parents:
diff changeset
1934 if (indirect)
kono
parents:
diff changeset
1935 {
kono
parents:
diff changeset
1936 // We don't know what happens to the parameters through indirect calls.
kono
parents:
diff changeset
1937 // Be conservative and assume they all flow to theSink.
kono
parents:
diff changeset
1938 for (std::vector<Node*>::iterator p = arg_nodes.begin();
kono
parents:
diff changeset
1939 p != arg_nodes.end();
kono
parents:
diff changeset
1940 ++p)
kono
parents:
diff changeset
1941 {
kono
parents:
diff changeset
1942 if (debug_level > 2)
kono
parents:
diff changeset
1943 go_inform(call->location(),
kono
parents:
diff changeset
1944 "esccall:: indirect call <- %s, untracked",
kono
parents:
diff changeset
1945 (*p)->ast_format(gogo).c_str());
kono
parents:
diff changeset
1946 this->assign(this->context_->sink(), *p);
kono
parents:
diff changeset
1947 }
kono
parents:
diff changeset
1948
kono
parents:
diff changeset
1949 this->context_->init_retvals(call_node, fntype);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1950
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1951 // It could be a closure call that returns captured variable.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1952 // Model this by flowing the func expression to result.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1953 // See issue #14409.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1954 Node* fn_node = Node::make_node(call->fn());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1955 std::vector<Node*> retvals = call_node->state(this->context_, NULL)->retvals;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1956 for (std::vector<Node*>::const_iterator p = retvals.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1957 p != retvals.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1958 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1959 this->assign_deref(*p, fn_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1960
111
kono
parents:
diff changeset
1961 return;
kono
parents:
diff changeset
1962 }
kono
parents:
diff changeset
1963
kono
parents:
diff changeset
1964 // If FN is an untagged function.
kono
parents:
diff changeset
1965 if (fn != NULL
kono
parents:
diff changeset
1966 && fn->named_object()->is_function()
kono
parents:
diff changeset
1967 && !fntype->is_tagged())
kono
parents:
diff changeset
1968 {
kono
parents:
diff changeset
1969 if (debug_level > 2)
kono
parents:
diff changeset
1970 go_inform(call->location(), "esccall:: %s in recursive group",
kono
parents:
diff changeset
1971 call_node->ast_format(gogo).c_str());
kono
parents:
diff changeset
1972
kono
parents:
diff changeset
1973 Function* f = fn->named_object()->func_value();
kono
parents:
diff changeset
1974 const Bindings* callee_bindings = f->block()->bindings();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1975 Function::Results* results = f->result_variables();
111
kono
parents:
diff changeset
1976 if (results != NULL)
kono
parents:
diff changeset
1977 {
kono
parents:
diff changeset
1978 // Setup output list on this call node.
kono
parents:
diff changeset
1979 Node::Escape_state* state = call_node->state(this->context_, NULL);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1980 for (Function::Results::const_iterator p1 = results->begin();
111
kono
parents:
diff changeset
1981 p1 != results->end();
kono
parents:
diff changeset
1982 ++p1)
kono
parents:
diff changeset
1983 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1984 Node* result_node = Node::make_node(*p1);
111
kono
parents:
diff changeset
1985 state->retvals.push_back(result_node);
kono
parents:
diff changeset
1986 }
kono
parents:
diff changeset
1987 }
kono
parents:
diff changeset
1988
kono
parents:
diff changeset
1989 std::vector<Node*>::iterator p = arg_nodes.begin();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1990 if (fntype->is_method())
111
kono
parents:
diff changeset
1991 {
kono
parents:
diff changeset
1992 std::string rcvr_name = fntype->receiver()->name();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1993 if (rcvr_name.empty() || Gogo::is_sink_name(rcvr_name)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1994 || !fntype->receiver()->type()->has_pointer())
111
kono
parents:
diff changeset
1995 ;
kono
parents:
diff changeset
1996 else
kono
parents:
diff changeset
1997 {
kono
parents:
diff changeset
1998 Named_object* rcvr_no =
kono
parents:
diff changeset
1999 callee_bindings->lookup_local(fntype->receiver()->name());
kono
parents:
diff changeset
2000 go_assert(rcvr_no != NULL);
kono
parents:
diff changeset
2001 Node* rcvr_node = Node::make_node(rcvr_no);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2002 if (fntype->receiver()->type()->points_to() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2003 && (*p)->expr()->type()->points_to() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2004 // This is a call to a value method that has been lowered into a call
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2005 // to a pointer method. Gccgo generates a pointer method for all
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2006 // method calls and takes the address of the value passed as the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2007 // receiver then immediately dereferences it within the function.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2008 // In this case, the receiver address does not escape; its content
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2009 // flows to the call.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2010 this->assign_deref(rcvr_node, *p);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2011 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2012 this->assign(rcvr_node, *p);
111
kono
parents:
diff changeset
2013 }
kono
parents:
diff changeset
2014 ++p;
kono
parents:
diff changeset
2015 }
kono
parents:
diff changeset
2016
kono
parents:
diff changeset
2017 const Typed_identifier_list* til = fntype->parameters();
kono
parents:
diff changeset
2018 if (til != NULL)
kono
parents:
diff changeset
2019 {
kono
parents:
diff changeset
2020 for (Typed_identifier_list::const_iterator p1 = til->begin();
kono
parents:
diff changeset
2021 p1 != til->end();
kono
parents:
diff changeset
2022 ++p1, ++p)
kono
parents:
diff changeset
2023 {
kono
parents:
diff changeset
2024 if (p1->name().empty() || Gogo::is_sink_name(p1->name()))
kono
parents:
diff changeset
2025 continue;
kono
parents:
diff changeset
2026
kono
parents:
diff changeset
2027 Named_object* param_no =
kono
parents:
diff changeset
2028 callee_bindings->lookup_local(p1->name());
kono
parents:
diff changeset
2029 go_assert(param_no != NULL);
kono
parents:
diff changeset
2030 Expression* arg = (*p)->expr();
kono
parents:
diff changeset
2031 if (arg->var_expression() != NULL
kono
parents:
diff changeset
2032 && arg->var_expression()->named_object() == param_no)
kono
parents:
diff changeset
2033 continue;
kono
parents:
diff changeset
2034
kono
parents:
diff changeset
2035 Node* param_node = Node::make_node(param_no);
kono
parents:
diff changeset
2036 this->assign(param_node, *p);
kono
parents:
diff changeset
2037 }
kono
parents:
diff changeset
2038
kono
parents:
diff changeset
2039 for (; p != arg_nodes.end(); ++p)
kono
parents:
diff changeset
2040 {
kono
parents:
diff changeset
2041 if (debug_level > 2)
kono
parents:
diff changeset
2042 go_inform(call->location(), "esccall:: ... <- %s, untracked",
kono
parents:
diff changeset
2043 (*p)->ast_format(gogo).c_str());
kono
parents:
diff changeset
2044 this->assign(this->context_->sink(), *p);
kono
parents:
diff changeset
2045 }
kono
parents:
diff changeset
2046 }
kono
parents:
diff changeset
2047
kono
parents:
diff changeset
2048 return;
kono
parents:
diff changeset
2049 }
kono
parents:
diff changeset
2050
kono
parents:
diff changeset
2051 if (debug_level > 2)
kono
parents:
diff changeset
2052 go_inform(call->location(), "esccall:: %s not recursive",
kono
parents:
diff changeset
2053 call_node->ast_format(gogo).c_str());
kono
parents:
diff changeset
2054
kono
parents:
diff changeset
2055 Node::Escape_state* call_state = call_node->state(this->context_, NULL);
kono
parents:
diff changeset
2056 if (!call_state->retvals.empty())
kono
parents:
diff changeset
2057 go_error_at(Linemap::unknown_location(),
kono
parents:
diff changeset
2058 "esc already decorated call %s",
kono
parents:
diff changeset
2059 call_node->ast_format(gogo).c_str());
kono
parents:
diff changeset
2060 this->context_->init_retvals(call_node, fntype);
kono
parents:
diff changeset
2061
kono
parents:
diff changeset
2062 // Receiver.
kono
parents:
diff changeset
2063 std::vector<Node*>::iterator p = arg_nodes.begin();
kono
parents:
diff changeset
2064 if (fntype->is_method()
kono
parents:
diff changeset
2065 && p != arg_nodes.end())
kono
parents:
diff changeset
2066 {
kono
parents:
diff changeset
2067 // First argument to call will be the receiver.
kono
parents:
diff changeset
2068 std::string* note = fntype->receiver()->note();
kono
parents:
diff changeset
2069 if (fntype->receiver()->type()->points_to() == NULL
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2070 && (*p)->expr()->type()->points_to() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2071 // This is a call to a value method that has been lowered into a call
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2072 // to a pointer method. Gccgo generates a pointer method for all
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2073 // method calls and takes the address of the value passed as the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2074 // receiver then immediately dereferences it within the function.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2075 // In this case, the receiver address does not escape; its content
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2076 // flows to the call.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2077 this->assign_from_note(note, call_state->retvals,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2078 this->context_->add_dereference(*p));
111
kono
parents:
diff changeset
2079 else
kono
parents:
diff changeset
2080 {
kono
parents:
diff changeset
2081 if (!Type::are_identical(fntype->receiver()->type(),
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2082 (*p)->expr()->type(), Type::COMPARE_TAGS,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2083 NULL))
111
kono
parents:
diff changeset
2084 {
kono
parents:
diff changeset
2085 // This will be converted later, preemptively track it instead
kono
parents:
diff changeset
2086 // of its conversion expression which will show up in a later pass.
kono
parents:
diff changeset
2087 this->context_->track(*p);
kono
parents:
diff changeset
2088 }
kono
parents:
diff changeset
2089 this->assign_from_note(note, call_state->retvals, *p);
kono
parents:
diff changeset
2090 }
kono
parents:
diff changeset
2091 p++;
kono
parents:
diff changeset
2092 }
kono
parents:
diff changeset
2093
kono
parents:
diff changeset
2094 const Typed_identifier_list* til = fntype->parameters();
kono
parents:
diff changeset
2095 if (til != NULL)
kono
parents:
diff changeset
2096 {
kono
parents:
diff changeset
2097 for (Typed_identifier_list::const_iterator pn = til->begin();
kono
parents:
diff changeset
2098 pn != til->end() && p != arg_nodes.end();
kono
parents:
diff changeset
2099 ++pn, ++p)
kono
parents:
diff changeset
2100 {
kono
parents:
diff changeset
2101 if (!Type::are_identical(pn->type(), (*p)->expr()->type(),
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2102 Type::COMPARE_TAGS, NULL))
111
kono
parents:
diff changeset
2103 {
kono
parents:
diff changeset
2104 // This will be converted later, preemptively track it instead
kono
parents:
diff changeset
2105 // of its conversion expression which will show up in a later pass.
kono
parents:
diff changeset
2106 this->context_->track(*p);
kono
parents:
diff changeset
2107 }
kono
parents:
diff changeset
2108
kono
parents:
diff changeset
2109 Type* t = pn->type();
kono
parents:
diff changeset
2110 if (t != NULL
kono
parents:
diff changeset
2111 && t->has_pointer())
kono
parents:
diff changeset
2112 {
kono
parents:
diff changeset
2113 std::string* note = pn->note();
kono
parents:
diff changeset
2114 int enc = this->assign_from_note(note, call_state->retvals, *p);
kono
parents:
diff changeset
2115 if (enc == Node::ESCAPE_NONE
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2116 && !call->is_deferred()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2117 && !call->is_concurrent())
111
kono
parents:
diff changeset
2118 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2119 // TODO(cmang): Mark the argument as strictly non-escaping?
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2120 // In the gc compiler this is for limiting the lifetime of
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2121 // temporaries. We probably don't need this?
111
kono
parents:
diff changeset
2122 }
kono
parents:
diff changeset
2123 }
kono
parents:
diff changeset
2124 }
kono
parents:
diff changeset
2125
kono
parents:
diff changeset
2126 for (; p != arg_nodes.end(); ++p)
kono
parents:
diff changeset
2127 {
kono
parents:
diff changeset
2128 if (debug_level > 2)
kono
parents:
diff changeset
2129 go_inform(call->location(), "esccall:: ... <- %s, untracked",
kono
parents:
diff changeset
2130 (*p)->ast_format(gogo).c_str());
kono
parents:
diff changeset
2131 this->assign(this->context_->sink(), *p);
kono
parents:
diff changeset
2132 }
kono
parents:
diff changeset
2133 }
kono
parents:
diff changeset
2134 }
kono
parents:
diff changeset
2135
kono
parents:
diff changeset
2136 // Model the assignment of DST to SRC.
kono
parents:
diff changeset
2137 // Assert that SRC somehow gets assigned to DST.
kono
parents:
diff changeset
2138 // DST might need to be examined for evaluations that happen inside of it.
kono
parents:
diff changeset
2139 // For example, in [DST]*f(x) = [SRC]y, we lose track of the indirection and
kono
parents:
diff changeset
2140 // DST becomes the sink in our model.
kono
parents:
diff changeset
2141
kono
parents:
diff changeset
2142 void
kono
parents:
diff changeset
2143 Escape_analysis_assign::assign(Node* dst, Node* src)
kono
parents:
diff changeset
2144 {
kono
parents:
diff changeset
2145 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
2146 int debug_level = gogo->debug_escape_level();
kono
parents:
diff changeset
2147 if (debug_level > 1)
kono
parents:
diff changeset
2148 go_inform(dst->location(), "[%d] %s escassign: %s(%s)[%s] = %s(%s)[%s]",
kono
parents:
diff changeset
2149 this->context_->loop_depth(),
kono
parents:
diff changeset
2150 strip_packed_prefix(gogo, this->context_->current_function_name()).c_str(),
kono
parents:
diff changeset
2151 dst->ast_format(gogo).c_str(), dst->details().c_str(),
kono
parents:
diff changeset
2152 dst->op_format().c_str(),
kono
parents:
diff changeset
2153 src->ast_format(gogo).c_str(), src->details().c_str(),
kono
parents:
diff changeset
2154 src->op_format().c_str());
kono
parents:
diff changeset
2155
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2156 if (dst->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2157 // Lose track of the dereference.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2158 dst = this->context_->sink();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2159 else if (dst->expr() != NULL)
111
kono
parents:
diff changeset
2160 {
kono
parents:
diff changeset
2161 // Analyze the lhs of the assignment.
kono
parents:
diff changeset
2162 // Replace DST with this->context_->sink() if we can't track it.
kono
parents:
diff changeset
2163 Expression* e = dst->expr();
kono
parents:
diff changeset
2164 switch (e->classification())
kono
parents:
diff changeset
2165 {
kono
parents:
diff changeset
2166 case Expression::EXPRESSION_VAR_REFERENCE:
kono
parents:
diff changeset
2167 {
kono
parents:
diff changeset
2168 // If DST is a global variable, we have no way to track it.
kono
parents:
diff changeset
2169 Named_object* var = e->var_expression()->named_object();
kono
parents:
diff changeset
2170 if (var->is_variable() && var->var_value()->is_global())
kono
parents:
diff changeset
2171 dst = this->context_->sink();
kono
parents:
diff changeset
2172 }
kono
parents:
diff changeset
2173 break;
kono
parents:
diff changeset
2174
kono
parents:
diff changeset
2175 case Expression::EXPRESSION_FIELD_REFERENCE:
kono
parents:
diff changeset
2176 {
kono
parents:
diff changeset
2177 Expression* strct = e->field_reference_expression()->expr();
kono
parents:
diff changeset
2178 if (strct->heap_expression() != NULL)
kono
parents:
diff changeset
2179 {
kono
parents:
diff changeset
2180 // When accessing the field of a struct reference, we lose
kono
parents:
diff changeset
2181 // track of the indirection.
kono
parents:
diff changeset
2182 dst = this->context_->sink();
kono
parents:
diff changeset
2183 break;
kono
parents:
diff changeset
2184 }
kono
parents:
diff changeset
2185
kono
parents:
diff changeset
2186 // Treat DST.x = SRC as if it were DST = SRC.
kono
parents:
diff changeset
2187 Node* struct_node = Node::make_node(strct);
kono
parents:
diff changeset
2188 this->assign(struct_node, src);
kono
parents:
diff changeset
2189 return;
kono
parents:
diff changeset
2190 }
kono
parents:
diff changeset
2191
kono
parents:
diff changeset
2192 case Expression::EXPRESSION_ARRAY_INDEX:
kono
parents:
diff changeset
2193 {
kono
parents:
diff changeset
2194 Array_index_expression* are = e->array_index_expression();
kono
parents:
diff changeset
2195 if (!are->array()->type()->is_slice_type())
kono
parents:
diff changeset
2196 {
kono
parents:
diff changeset
2197 // Treat DST[i] = SRC as if it were DST = SRC if DST if a fixed
kono
parents:
diff changeset
2198 // array.
kono
parents:
diff changeset
2199 Node* array_node = Node::make_node(are->array());
kono
parents:
diff changeset
2200 this->assign(array_node, src);
kono
parents:
diff changeset
2201 return;
kono
parents:
diff changeset
2202 }
kono
parents:
diff changeset
2203
kono
parents:
diff changeset
2204 // Lose track of the slice dereference.
kono
parents:
diff changeset
2205 dst = this->context_->sink();
kono
parents:
diff changeset
2206 }
kono
parents:
diff changeset
2207 break;
kono
parents:
diff changeset
2208
kono
parents:
diff changeset
2209 case Expression::EXPRESSION_UNARY:
kono
parents:
diff changeset
2210 // Lose track of the dereference.
kono
parents:
diff changeset
2211 if (e->unary_expression()->op() == OPERATOR_MULT)
kono
parents:
diff changeset
2212 dst = this->context_->sink();
kono
parents:
diff changeset
2213 break;
kono
parents:
diff changeset
2214
kono
parents:
diff changeset
2215 case Expression::EXPRESSION_MAP_INDEX:
kono
parents:
diff changeset
2216 {
kono
parents:
diff changeset
2217 // Lose track of the map's key and value.
kono
parents:
diff changeset
2218 Expression* index = e->map_index_expression()->index();
kono
parents:
diff changeset
2219 Node* index_node = Node::make_node(index);
kono
parents:
diff changeset
2220 this->assign(this->context_->sink(), index_node);
kono
parents:
diff changeset
2221
kono
parents:
diff changeset
2222 dst = this->context_->sink();
kono
parents:
diff changeset
2223 }
kono
parents:
diff changeset
2224 break;
kono
parents:
diff changeset
2225
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2226 case Expression::EXPRESSION_TEMPORARY_REFERENCE:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2227 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2228 // Temporary is tracked through the underlying Temporary_statement.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2229 Temporary_statement* t =
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2230 dst->expr()->temporary_reference_expression()->statement();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2231 if (t->value_escapes())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2232 dst = this->context_->sink();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2233 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2234 dst = Node::make_node(t);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2235 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2236 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2237
111
kono
parents:
diff changeset
2238 default:
kono
parents:
diff changeset
2239 // TODO(cmang): Add debugging info here: only a few expressions
kono
parents:
diff changeset
2240 // should leave DST unmodified.
kono
parents:
diff changeset
2241 break;
kono
parents:
diff changeset
2242 }
kono
parents:
diff changeset
2243 }
kono
parents:
diff changeset
2244
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2245 if (src->object() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2246 this->flows(dst, src);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2247 else if (src->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2248 this->flows(dst, src);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2249 else if (src->expr() != NULL)
111
kono
parents:
diff changeset
2250 {
kono
parents:
diff changeset
2251 Expression* e = src->expr();
kono
parents:
diff changeset
2252 switch (e->classification())
kono
parents:
diff changeset
2253 {
kono
parents:
diff changeset
2254 case Expression::EXPRESSION_VAR_REFERENCE:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2255 case Expression::EXPRESSION_ENCLOSED_VAR_REFERENCE:
111
kono
parents:
diff changeset
2256 // DST = var
kono
parents:
diff changeset
2257 case Expression::EXPRESSION_HEAP:
kono
parents:
diff changeset
2258 // DST = &T{...}.
kono
parents:
diff changeset
2259 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
kono
parents:
diff changeset
2260 case Expression::EXPRESSION_SLICE_CONSTRUCTION:
kono
parents:
diff changeset
2261 // DST = [...]T{...}.
kono
parents:
diff changeset
2262 case Expression::EXPRESSION_MAP_CONSTRUCTION:
kono
parents:
diff changeset
2263 // DST = map[T]V{...}.
kono
parents:
diff changeset
2264 case Expression::EXPRESSION_STRUCT_CONSTRUCTION:
kono
parents:
diff changeset
2265 // DST = T{...}.
kono
parents:
diff changeset
2266 case Expression::EXPRESSION_ALLOCATION:
kono
parents:
diff changeset
2267 // DST = new(T).
kono
parents:
diff changeset
2268 case Expression::EXPRESSION_BOUND_METHOD:
kono
parents:
diff changeset
2269 // DST = x.M.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2270 case Expression::EXPRESSION_STRING_CONCAT:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2271 // DST = str1 + str2
111
kono
parents:
diff changeset
2272 this->flows(dst, src);
kono
parents:
diff changeset
2273 break;
kono
parents:
diff changeset
2274
kono
parents:
diff changeset
2275 case Expression::EXPRESSION_UNSAFE_CONVERSION:
kono
parents:
diff changeset
2276 {
kono
parents:
diff changeset
2277 Expression* underlying = e->unsafe_conversion_expression()->expr();
kono
parents:
diff changeset
2278 Node* underlying_node = Node::make_node(underlying);
kono
parents:
diff changeset
2279 this->assign(dst, underlying_node);
kono
parents:
diff changeset
2280 }
kono
parents:
diff changeset
2281 break;
kono
parents:
diff changeset
2282
kono
parents:
diff changeset
2283 case Expression::EXPRESSION_CALL:
kono
parents:
diff changeset
2284 {
kono
parents:
diff changeset
2285 Call_expression* call = e->call_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2286 if (call->is_builtin())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2287 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2288 Builtin_call_expression* bce = call->builtin_call_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2289 if (bce->code() == Builtin_call_expression::BUILTIN_APPEND)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2290 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2291 // Append returns the first argument.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2292 // The subsequent arguments are already leaked because
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2293 // they are operands to append.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2294 Node* appendee = Node::make_node(call->args()->front());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2295 this->assign(dst, appendee);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2296 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2297 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2298 }
111
kono
parents:
diff changeset
2299 Func_expression* fe = call->fn()->func_expression();
kono
parents:
diff changeset
2300 if (fe != NULL && fe->is_runtime_function())
kono
parents:
diff changeset
2301 {
kono
parents:
diff changeset
2302 switch (fe->runtime_code())
kono
parents:
diff changeset
2303 {
kono
parents:
diff changeset
2304 case Runtime::MAKECHAN:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2305 case Runtime::MAKECHAN64:
111
kono
parents:
diff changeset
2306 case Runtime::MAKEMAP:
kono
parents:
diff changeset
2307 case Runtime::MAKESLICE:
kono
parents:
diff changeset
2308 case Runtime::MAKESLICE64:
kono
parents:
diff changeset
2309 // DST = make(...).
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2310 this->flows(dst, src);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2311 break;
111
kono
parents:
diff changeset
2312
kono
parents:
diff changeset
2313 default:
kono
parents:
diff changeset
2314 break;
kono
parents:
diff changeset
2315 }
kono
parents:
diff changeset
2316 break;
kono
parents:
diff changeset
2317 }
kono
parents:
diff changeset
2318 else if (fe != NULL
kono
parents:
diff changeset
2319 && fe->named_object()->is_function()
kono
parents:
diff changeset
2320 && fe->named_object()->func_value()->is_method()
kono
parents:
diff changeset
2321 && (call->is_deferred()
kono
parents:
diff changeset
2322 || call->is_concurrent()))
kono
parents:
diff changeset
2323 {
kono
parents:
diff changeset
2324 // For a method call thunk, lose track of the call and treat it
kono
parents:
diff changeset
2325 // as if DST = RECEIVER.
kono
parents:
diff changeset
2326 Node* rcvr_node = Node::make_node(call->args()->front());
kono
parents:
diff changeset
2327 this->assign(dst, rcvr_node);
kono
parents:
diff changeset
2328 break;
kono
parents:
diff changeset
2329 }
kono
parents:
diff changeset
2330
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2331 // Result flows to dst.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2332 Node* call_node = Node::make_node(e);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2333 Node::Escape_state* call_state = call_node->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2334 std::vector<Node*> retvals = call_state->retvals;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2335 for (std::vector<Node*>::const_iterator p = retvals.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2336 p != retvals.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2337 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2338 this->flows(dst, *p);
111
kono
parents:
diff changeset
2339 }
kono
parents:
diff changeset
2340 break;
kono
parents:
diff changeset
2341
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2342 case Expression::EXPRESSION_CALL_RESULT:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2343 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2344 Call_result_expression* cre = e->call_result_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2345 Call_expression* call = cre->call()->call_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2346 if (call->is_builtin())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2347 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2348 if (call->fn()->func_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2349 && call->fn()->func_expression()->is_runtime_function())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2350 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2351 switch (call->fn()->func_expression()->runtime_code())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2352 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2353 case Runtime::IFACEE2E2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2354 case Runtime::IFACEI2E2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2355 case Runtime::IFACEE2I2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2356 case Runtime::IFACEI2I2:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2357 case Runtime::IFACEE2T2P:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2358 case Runtime::IFACEI2T2P:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2359 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2360 // x, ok = v.(T), where T is a pointer or interface,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2361 // is lowered to
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2362 // x, ok = IFACEI2E2(v), or
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2363 // x, ok = IFACEI2I2(type, v)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2364 // The last arg flows to the first result.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2365 // Note: IFACEX2T2 has different signature, handled by
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2366 // ::expression.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2367 if (cre->index() != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2368 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2369 Node* arg_node = Node::make_node(call->args()->back());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2370 this->assign(dst, arg_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2371 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2372 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2373
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2374 default:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2375 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2376 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2377 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2378 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2379
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2380 Node* call_node = Node::make_node(call);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2381 Node* ret_node = call_node->state(context_, NULL)->retvals[cre->index()];
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2382 this->assign(dst, ret_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2383 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2384 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2385
111
kono
parents:
diff changeset
2386 case Expression::EXPRESSION_FUNC_REFERENCE:
kono
parents:
diff changeset
2387 if (e->func_expression()->closure() != NULL)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2388 this->flows(dst, src);
111
kono
parents:
diff changeset
2389 break;
kono
parents:
diff changeset
2390
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2391 case Expression::EXPRESSION_CONVERSION:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2392 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2393 Type_conversion_expression* tce = e->conversion_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2394 Type* ft = tce->expr()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2395 Type* tt = tce->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2396 if ((ft->is_string_type() && tt->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2397 || (ft->is_slice_type() && tt->is_string_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2398 || (ft->integer_type() != NULL && tt->is_string_type()))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2399 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2400 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2401 this->flows(dst, src);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2402 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2403 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2404 // Conversion preserves input value.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2405 Expression* underlying = tce->expr();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2406 this->assign(dst, Node::make_node(underlying));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2407 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2408 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2409
111
kono
parents:
diff changeset
2410 case Expression::EXPRESSION_FIELD_REFERENCE:
kono
parents:
diff changeset
2411 {
kono
parents:
diff changeset
2412 // A non-pointer can't escape from a struct.
kono
parents:
diff changeset
2413 if (!e->type()->has_pointer())
kono
parents:
diff changeset
2414 break;
kono
parents:
diff changeset
2415 }
kono
parents:
diff changeset
2416 // Fall through.
kono
parents:
diff changeset
2417
kono
parents:
diff changeset
2418 case Expression::EXPRESSION_TYPE_GUARD:
kono
parents:
diff changeset
2419 case Expression::EXPRESSION_ARRAY_INDEX:
kono
parents:
diff changeset
2420 case Expression::EXPRESSION_STRING_INDEX:
kono
parents:
diff changeset
2421 {
kono
parents:
diff changeset
2422 Expression* left = NULL;
kono
parents:
diff changeset
2423 if (e->field_reference_expression() != NULL)
kono
parents:
diff changeset
2424 {
kono
parents:
diff changeset
2425 left = e->field_reference_expression()->expr();
kono
parents:
diff changeset
2426 if (left->unary_expression() != NULL
kono
parents:
diff changeset
2427 && left->unary_expression()->op() == OPERATOR_MULT)
kono
parents:
diff changeset
2428 {
kono
parents:
diff changeset
2429 // DST = (*x).f
kono
parents:
diff changeset
2430 this->flows(dst, src);
kono
parents:
diff changeset
2431 break;
kono
parents:
diff changeset
2432 }
kono
parents:
diff changeset
2433 }
kono
parents:
diff changeset
2434 else if (e->type_guard_expression() != NULL)
kono
parents:
diff changeset
2435 left = e->type_guard_expression()->expr();
kono
parents:
diff changeset
2436 else if (e->array_index_expression() != NULL)
kono
parents:
diff changeset
2437 {
kono
parents:
diff changeset
2438 Array_index_expression* aie = e->array_index_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2439 if (aie->end() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2440 // slicing
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2441 if (aie->array()->type()->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2442 left = aie->array();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2443 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2444 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2445 // slicing an array
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2446 // The gc compiler has an implicit address operator.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2447 go_assert(src->child() != NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2448 this->assign(dst, src->child());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2449 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2450 }
111
kono
parents:
diff changeset
2451 else if (!aie->array()->type()->is_slice_type())
kono
parents:
diff changeset
2452 {
kono
parents:
diff changeset
2453 // Indexing an array preserves the input value.
kono
parents:
diff changeset
2454 Node* array_node = Node::make_node(aie->array());
kono
parents:
diff changeset
2455 this->assign(dst, array_node);
kono
parents:
diff changeset
2456 break;
kono
parents:
diff changeset
2457 }
kono
parents:
diff changeset
2458 else
kono
parents:
diff changeset
2459 {
kono
parents:
diff changeset
2460 this->flows(dst, src);
kono
parents:
diff changeset
2461 break;
kono
parents:
diff changeset
2462 }
kono
parents:
diff changeset
2463 }
kono
parents:
diff changeset
2464 else if (e->string_index_expression() != NULL)
kono
parents:
diff changeset
2465 {
kono
parents:
diff changeset
2466 String_index_expression* sie = e->string_index_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2467 if (e->type()->is_string_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2468 // slicing
111
kono
parents:
diff changeset
2469 left = sie->string();
kono
parents:
diff changeset
2470 else
kono
parents:
diff changeset
2471 {
kono
parents:
diff changeset
2472 this->flows(dst, src);
kono
parents:
diff changeset
2473 break;
kono
parents:
diff changeset
2474 }
kono
parents:
diff changeset
2475 }
kono
parents:
diff changeset
2476 go_assert(left != NULL);
kono
parents:
diff changeset
2477
kono
parents:
diff changeset
2478 // Conversions, field access, and slicing all preserve the input
kono
parents:
diff changeset
2479 // value.
kono
parents:
diff changeset
2480 Node* left_node = Node::make_node(left);
kono
parents:
diff changeset
2481 this->assign(dst, left_node);
kono
parents:
diff changeset
2482 }
kono
parents:
diff changeset
2483 break;
kono
parents:
diff changeset
2484
kono
parents:
diff changeset
2485 case Expression::EXPRESSION_BINARY:
kono
parents:
diff changeset
2486 {
kono
parents:
diff changeset
2487 switch (e->binary_expression()->op())
kono
parents:
diff changeset
2488 {
kono
parents:
diff changeset
2489 case OPERATOR_PLUS:
kono
parents:
diff changeset
2490 case OPERATOR_MINUS:
kono
parents:
diff changeset
2491 case OPERATOR_XOR:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2492 case OPERATOR_OR:
111
kono
parents:
diff changeset
2493 case OPERATOR_MULT:
kono
parents:
diff changeset
2494 case OPERATOR_DIV:
kono
parents:
diff changeset
2495 case OPERATOR_MOD:
kono
parents:
diff changeset
2496 case OPERATOR_LSHIFT:
kono
parents:
diff changeset
2497 case OPERATOR_RSHIFT:
kono
parents:
diff changeset
2498 case OPERATOR_AND:
kono
parents:
diff changeset
2499 case OPERATOR_BITCLEAR:
kono
parents:
diff changeset
2500 {
kono
parents:
diff changeset
2501 Node* left = Node::make_node(e->binary_expression()->left());
kono
parents:
diff changeset
2502 this->assign(dst, left);
kono
parents:
diff changeset
2503 Node* right = Node::make_node(e->binary_expression()->right());
kono
parents:
diff changeset
2504 this->assign(dst, right);
kono
parents:
diff changeset
2505 }
kono
parents:
diff changeset
2506 break;
kono
parents:
diff changeset
2507
kono
parents:
diff changeset
2508 default:
kono
parents:
diff changeset
2509 break;
kono
parents:
diff changeset
2510 }
kono
parents:
diff changeset
2511 }
kono
parents:
diff changeset
2512 break;
kono
parents:
diff changeset
2513
kono
parents:
diff changeset
2514 case Expression::EXPRESSION_UNARY:
kono
parents:
diff changeset
2515 {
kono
parents:
diff changeset
2516 switch (e->unary_expression()->op())
kono
parents:
diff changeset
2517 {
kono
parents:
diff changeset
2518 case OPERATOR_PLUS:
kono
parents:
diff changeset
2519 case OPERATOR_MINUS:
kono
parents:
diff changeset
2520 case OPERATOR_XOR:
kono
parents:
diff changeset
2521 {
kono
parents:
diff changeset
2522 Node* op_node =
kono
parents:
diff changeset
2523 Node::make_node(e->unary_expression()->operand());
kono
parents:
diff changeset
2524 this->assign(dst, op_node);
kono
parents:
diff changeset
2525 }
kono
parents:
diff changeset
2526 break;
kono
parents:
diff changeset
2527
kono
parents:
diff changeset
2528 case OPERATOR_MULT:
kono
parents:
diff changeset
2529 // DST = *x
kono
parents:
diff changeset
2530 case OPERATOR_AND:
kono
parents:
diff changeset
2531 // DST = &x
kono
parents:
diff changeset
2532 this->flows(dst, src);
kono
parents:
diff changeset
2533 break;
kono
parents:
diff changeset
2534
kono
parents:
diff changeset
2535 default:
kono
parents:
diff changeset
2536 break;
kono
parents:
diff changeset
2537 }
kono
parents:
diff changeset
2538 }
kono
parents:
diff changeset
2539 break;
kono
parents:
diff changeset
2540
kono
parents:
diff changeset
2541 case Expression::EXPRESSION_TEMPORARY_REFERENCE:
kono
parents:
diff changeset
2542 {
kono
parents:
diff changeset
2543 Statement* temp = e->temporary_reference_expression()->statement();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2544 this->assign(dst, Node::make_node(temp));
111
kono
parents:
diff changeset
2545 }
kono
parents:
diff changeset
2546 break;
kono
parents:
diff changeset
2547
kono
parents:
diff changeset
2548 default:
kono
parents:
diff changeset
2549 // TODO(cmang): Add debug info here; this should not be reachable.
kono
parents:
diff changeset
2550 // For now, just to be conservative, we'll just say dst flows to src.
kono
parents:
diff changeset
2551 break;
kono
parents:
diff changeset
2552 }
kono
parents:
diff changeset
2553 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2554 else if (src->statement() != NULL && src->statement()->temporary_statement() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2555 this->flows(dst, src);
111
kono
parents:
diff changeset
2556 }
kono
parents:
diff changeset
2557
kono
parents:
diff changeset
2558 // Model the assignment of DST to an indirection of SRC.
kono
parents:
diff changeset
2559
kono
parents:
diff changeset
2560 void
kono
parents:
diff changeset
2561 Escape_analysis_assign::assign_deref(Node* dst, Node* src)
kono
parents:
diff changeset
2562 {
kono
parents:
diff changeset
2563 if (src->expr() != NULL)
kono
parents:
diff changeset
2564 {
kono
parents:
diff changeset
2565 switch (src->expr()->classification())
kono
parents:
diff changeset
2566 {
kono
parents:
diff changeset
2567 case Expression::EXPRESSION_BOOLEAN:
kono
parents:
diff changeset
2568 case Expression::EXPRESSION_STRING:
kono
parents:
diff changeset
2569 case Expression::EXPRESSION_INTEGER:
kono
parents:
diff changeset
2570 case Expression::EXPRESSION_FLOAT:
kono
parents:
diff changeset
2571 case Expression::EXPRESSION_COMPLEX:
kono
parents:
diff changeset
2572 case Expression::EXPRESSION_NIL:
kono
parents:
diff changeset
2573 case Expression::EXPRESSION_IOTA:
kono
parents:
diff changeset
2574 // No need to try indirections on literal values
kono
parents:
diff changeset
2575 // or numeric constants.
kono
parents:
diff changeset
2576 return;
kono
parents:
diff changeset
2577
kono
parents:
diff changeset
2578 default:
kono
parents:
diff changeset
2579 break;
kono
parents:
diff changeset
2580 }
kono
parents:
diff changeset
2581 }
kono
parents:
diff changeset
2582
kono
parents:
diff changeset
2583 this->assign(dst, this->context_->add_dereference(src));
kono
parents:
diff changeset
2584 }
kono
parents:
diff changeset
2585
kono
parents:
diff changeset
2586 // Model the input-to-output assignment flow of one of a function call's
kono
parents:
diff changeset
2587 // arguments, where the flow is encoded in NOTE.
kono
parents:
diff changeset
2588
kono
parents:
diff changeset
2589 int
kono
parents:
diff changeset
2590 Escape_analysis_assign::assign_from_note(std::string* note,
kono
parents:
diff changeset
2591 const std::vector<Node*>& dsts,
kono
parents:
diff changeset
2592 Node* src)
kono
parents:
diff changeset
2593 {
kono
parents:
diff changeset
2594 int enc = Escape_note::parse_tag(note);
kono
parents:
diff changeset
2595 if (src->expr() != NULL)
kono
parents:
diff changeset
2596 {
kono
parents:
diff changeset
2597 switch (src->expr()->classification())
kono
parents:
diff changeset
2598 {
kono
parents:
diff changeset
2599 case Expression::EXPRESSION_BOOLEAN:
kono
parents:
diff changeset
2600 case Expression::EXPRESSION_STRING:
kono
parents:
diff changeset
2601 case Expression::EXPRESSION_INTEGER:
kono
parents:
diff changeset
2602 case Expression::EXPRESSION_FLOAT:
kono
parents:
diff changeset
2603 case Expression::EXPRESSION_COMPLEX:
kono
parents:
diff changeset
2604 case Expression::EXPRESSION_NIL:
kono
parents:
diff changeset
2605 case Expression::EXPRESSION_IOTA:
kono
parents:
diff changeset
2606 // There probably isn't a note for a literal value. Literal values
kono
parents:
diff changeset
2607 // usually don't escape unless we lost track of the value some how.
kono
parents:
diff changeset
2608 return enc;
kono
parents:
diff changeset
2609
kono
parents:
diff changeset
2610 default:
kono
parents:
diff changeset
2611 break;
kono
parents:
diff changeset
2612 }
kono
parents:
diff changeset
2613 }
kono
parents:
diff changeset
2614
kono
parents:
diff changeset
2615 if (this->context_->gogo()->debug_escape_level() > 2)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2616 go_inform(src->location(), "assignfromtag:: src=%s em=%s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2617 src->ast_format(context_->gogo()).c_str(),
111
kono
parents:
diff changeset
2618 Escape_note::make_tag(enc).c_str());
kono
parents:
diff changeset
2619
kono
parents:
diff changeset
2620 if (enc == Node::ESCAPE_UNKNOWN)
kono
parents:
diff changeset
2621 {
kono
parents:
diff changeset
2622 // Lost track of the value.
kono
parents:
diff changeset
2623 this->assign(this->context_->sink(), src);
kono
parents:
diff changeset
2624 return enc;
kono
parents:
diff changeset
2625 }
kono
parents:
diff changeset
2626 else if (enc == Node::ESCAPE_NONE)
kono
parents:
diff changeset
2627 return enc;
kono
parents:
diff changeset
2628
kono
parents:
diff changeset
2629 // If the content inside a parameter (reached via indirection) escapes to
kono
parents:
diff changeset
2630 // the heap, mark it.
kono
parents:
diff changeset
2631 if ((enc & ESCAPE_CONTENT_ESCAPES) != 0)
kono
parents:
diff changeset
2632 this->assign(this->context_->sink(), this->context_->add_dereference(src));
kono
parents:
diff changeset
2633
kono
parents:
diff changeset
2634 int save_enc = enc;
kono
parents:
diff changeset
2635 enc >>= ESCAPE_RETURN_BITS;
kono
parents:
diff changeset
2636 for (std::vector<Node*>::const_iterator p = dsts.begin();
kono
parents:
diff changeset
2637 enc != 0 && p != dsts.end();
kono
parents:
diff changeset
2638 ++p)
kono
parents:
diff changeset
2639 {
kono
parents:
diff changeset
2640 // Prefer the lowest-level path to the reference (for escape purposes).
kono
parents:
diff changeset
2641 // Two-bit encoding (for example. 1, 3, and 4 bits are other options)
kono
parents:
diff changeset
2642 // 01 = 0-level
kono
parents:
diff changeset
2643 // 10 = 1-level, (content escapes),
kono
parents:
diff changeset
2644 // 11 = 2-level, (content of content escapes).
kono
parents:
diff changeset
2645 int bits = enc & ESCAPE_BITS_MASK_FOR_TAG;
kono
parents:
diff changeset
2646 if (bits > 0)
kono
parents:
diff changeset
2647 {
kono
parents:
diff changeset
2648 Node* n = src;
kono
parents:
diff changeset
2649 for (int i = 0; i < bits - 1; ++i)
kono
parents:
diff changeset
2650 {
kono
parents:
diff changeset
2651 // Encode level > 0 as indirections.
kono
parents:
diff changeset
2652 n = this->context_->add_dereference(n);
kono
parents:
diff changeset
2653 }
kono
parents:
diff changeset
2654 this->assign(*p, n);
kono
parents:
diff changeset
2655 }
kono
parents:
diff changeset
2656 enc >>= ESCAPE_BITS_PER_OUTPUT_IN_TAG;
kono
parents:
diff changeset
2657 }
kono
parents:
diff changeset
2658
kono
parents:
diff changeset
2659 // If there are too many outputs to fit in the tag, that is handled on the
kono
parents:
diff changeset
2660 // encoding end as ESCAPE_HEAP, so there is no need to check here.
kono
parents:
diff changeset
2661 return save_enc;
kono
parents:
diff changeset
2662 }
kono
parents:
diff changeset
2663
kono
parents:
diff changeset
2664 // Record the flow of SRC to DST in DST.
kono
parents:
diff changeset
2665
kono
parents:
diff changeset
2666 void
kono
parents:
diff changeset
2667 Escape_analysis_assign::flows(Node* dst, Node* src)
kono
parents:
diff changeset
2668 {
kono
parents:
diff changeset
2669 // Don't bother capturing the flow from scalars.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2670 if (src->type() != NULL && !src->type()->has_pointer())
111
kono
parents:
diff changeset
2671 return;
kono
parents:
diff changeset
2672
kono
parents:
diff changeset
2673 // Don't confuse a blank identifier with the sink.
kono
parents:
diff changeset
2674 if (dst->is_sink() && dst != this->context_->sink())
kono
parents:
diff changeset
2675 return;
kono
parents:
diff changeset
2676
kono
parents:
diff changeset
2677 Node::Escape_state* dst_state = dst->state(this->context_, NULL);
kono
parents:
diff changeset
2678 Node::Escape_state* src_state = src->state(this->context_, NULL);
kono
parents:
diff changeset
2679 if (dst == src
kono
parents:
diff changeset
2680 || dst_state == src_state
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2681 || dst_state->flows.find(src) != dst_state->flows.end())
111
kono
parents:
diff changeset
2682 return;
kono
parents:
diff changeset
2683
kono
parents:
diff changeset
2684 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
2685 if (gogo->debug_escape_level() > 2)
kono
parents:
diff changeset
2686 go_inform(Linemap::unknown_location(), "flows:: %s <- %s",
kono
parents:
diff changeset
2687 dst->ast_format(gogo).c_str(), src->ast_format(gogo).c_str());
kono
parents:
diff changeset
2688
kono
parents:
diff changeset
2689 if (dst_state->flows.empty())
kono
parents:
diff changeset
2690 this->context_->add_dst(dst);
kono
parents:
diff changeset
2691
kono
parents:
diff changeset
2692 dst_state->flows.insert(src);
kono
parents:
diff changeset
2693 }
kono
parents:
diff changeset
2694
kono
parents:
diff changeset
2695 // Build a connectivity graph between nodes in the function being analyzed.
kono
parents:
diff changeset
2696
kono
parents:
diff changeset
2697 void
kono
parents:
diff changeset
2698 Gogo::assign_connectivity(Escape_context* context, Named_object* fn)
kono
parents:
diff changeset
2699 {
kono
parents:
diff changeset
2700 // Must be defined outside of this package.
kono
parents:
diff changeset
2701 if (!fn->is_function())
kono
parents:
diff changeset
2702 return;
kono
parents:
diff changeset
2703
kono
parents:
diff changeset
2704 int save_depth = context->loop_depth();
kono
parents:
diff changeset
2705 context->set_loop_depth(1);
kono
parents:
diff changeset
2706
kono
parents:
diff changeset
2707 Escape_analysis_assign ea(context, fn);
kono
parents:
diff changeset
2708 Function::Results* res = fn->func_value()->result_variables();
kono
parents:
diff changeset
2709 if (res != NULL)
kono
parents:
diff changeset
2710 {
kono
parents:
diff changeset
2711 for (Function::Results::const_iterator p = res->begin();
kono
parents:
diff changeset
2712 p != res->end();
kono
parents:
diff changeset
2713 ++p)
kono
parents:
diff changeset
2714 {
kono
parents:
diff changeset
2715 Node* res_node = Node::make_node(*p);
kono
parents:
diff changeset
2716 Node::Escape_state* res_state = res_node->state(context, fn);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2717 res_state->fn = fn;
111
kono
parents:
diff changeset
2718 res_state->loop_depth = 0;
kono
parents:
diff changeset
2719
kono
parents:
diff changeset
2720 // If this set of functions is recursive, we lose track of the return values.
kono
parents:
diff changeset
2721 // Just say that the result flows to the sink.
kono
parents:
diff changeset
2722 if (context->recursive())
kono
parents:
diff changeset
2723 ea.flows(context->sink(), res_node);
kono
parents:
diff changeset
2724 }
kono
parents:
diff changeset
2725 }
kono
parents:
diff changeset
2726
kono
parents:
diff changeset
2727 const Bindings* callee_bindings = fn->func_value()->block()->bindings();
kono
parents:
diff changeset
2728 Function_type* fntype = fn->func_value()->type();
kono
parents:
diff changeset
2729 Typed_identifier_list* params = (fntype->parameters() != NULL
kono
parents:
diff changeset
2730 ? fntype->parameters()->copy()
kono
parents:
diff changeset
2731 : new Typed_identifier_list);
kono
parents:
diff changeset
2732 if (fntype->receiver() != NULL)
kono
parents:
diff changeset
2733 params->push_back(*fntype->receiver());
kono
parents:
diff changeset
2734
kono
parents:
diff changeset
2735 for (Typed_identifier_list::const_iterator p = params->begin();
kono
parents:
diff changeset
2736 p != params->end();
kono
parents:
diff changeset
2737 ++p)
kono
parents:
diff changeset
2738 {
kono
parents:
diff changeset
2739 if (p->name().empty() || Gogo::is_sink_name(p->name()))
kono
parents:
diff changeset
2740 continue;
kono
parents:
diff changeset
2741
kono
parents:
diff changeset
2742 Named_object* param_no = callee_bindings->lookup_local(p->name());
kono
parents:
diff changeset
2743 go_assert(param_no != NULL);
kono
parents:
diff changeset
2744 Node* param_node = Node::make_node(param_no);
kono
parents:
diff changeset
2745 Node::Escape_state* param_state = param_node->state(context, fn);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2746 param_state->fn = fn;
111
kono
parents:
diff changeset
2747 param_state->loop_depth = 1;
kono
parents:
diff changeset
2748
kono
parents:
diff changeset
2749 if (!p->type()->has_pointer())
kono
parents:
diff changeset
2750 continue;
kono
parents:
diff changeset
2751
kono
parents:
diff changeset
2752 // External function? Parameters must escape unless //go:noescape is set.
kono
parents:
diff changeset
2753 // TODO(cmang): Implement //go:noescape directive.
kono
parents:
diff changeset
2754 if (fn->package() != NULL)
kono
parents:
diff changeset
2755 param_node->set_encoding(Node::ESCAPE_HEAP);
kono
parents:
diff changeset
2756 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2757 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2758 param_node->set_encoding(Node::ESCAPE_NONE);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2759 context->track(param_node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2760 }
111
kono
parents:
diff changeset
2761 }
kono
parents:
diff changeset
2762
kono
parents:
diff changeset
2763 Escape_analysis_loop el;
kono
parents:
diff changeset
2764 fn->func_value()->traverse(&el);
kono
parents:
diff changeset
2765
kono
parents:
diff changeset
2766 fn->func_value()->traverse(&ea);
kono
parents:
diff changeset
2767 context->set_loop_depth(save_depth);
kono
parents:
diff changeset
2768 }
kono
parents:
diff changeset
2769
kono
parents:
diff changeset
2770 class Escape_analysis_flood
kono
parents:
diff changeset
2771 {
kono
parents:
diff changeset
2772 public:
kono
parents:
diff changeset
2773 Escape_analysis_flood(Escape_context* context)
kono
parents:
diff changeset
2774 : context_(context)
kono
parents:
diff changeset
2775 { }
kono
parents:
diff changeset
2776
kono
parents:
diff changeset
2777 // Use the escape information in dst to update the escape information in src
kono
parents:
diff changeset
2778 // and src's upstream.
kono
parents:
diff changeset
2779 void
kono
parents:
diff changeset
2780 flood(Level, Node* dst, Node* src, int);
kono
parents:
diff changeset
2781
kono
parents:
diff changeset
2782 private:
kono
parents:
diff changeset
2783 // The escape context for the group of functions being flooded.
kono
parents:
diff changeset
2784 Escape_context* context_;
kono
parents:
diff changeset
2785 };
kono
parents:
diff changeset
2786
kono
parents:
diff changeset
2787 // Whenever we hit a dereference node, the level goes up by one, and whenever
kono
parents:
diff changeset
2788 // we hit an address-of, the level goes down by one. as long as we're on a
kono
parents:
diff changeset
2789 // level > 0 finding an address-of just means we're following the upstream
kono
parents:
diff changeset
2790 // of a dereference, so this address doesn't leak (yet).
kono
parents:
diff changeset
2791 // If level == 0, it means the /value/ of this node can reach the root of this
kono
parents:
diff changeset
2792 // flood so if this node is an address-of, its argument should be marked as
kono
parents:
diff changeset
2793 // escaping iff its current function and loop depth are different from the
kono
parents:
diff changeset
2794 // flood's root.
kono
parents:
diff changeset
2795 // Once an object has been moved to the heap, all of its upstream should be
kono
parents:
diff changeset
2796 // considered escaping to the global scope.
kono
parents:
diff changeset
2797 // This is an implementation of gc/esc.go:escwalkBody.
kono
parents:
diff changeset
2798
kono
parents:
diff changeset
2799 void
kono
parents:
diff changeset
2800 Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
kono
parents:
diff changeset
2801 int extra_loop_depth)
kono
parents:
diff changeset
2802 {
kono
parents:
diff changeset
2803 // No need to flood src if it is a literal.
kono
parents:
diff changeset
2804 if (src->expr() != NULL)
kono
parents:
diff changeset
2805 {
kono
parents:
diff changeset
2806 switch (src->expr()->classification())
kono
parents:
diff changeset
2807 {
kono
parents:
diff changeset
2808 case Expression::EXPRESSION_BOOLEAN:
kono
parents:
diff changeset
2809 case Expression::EXPRESSION_STRING:
kono
parents:
diff changeset
2810 case Expression::EXPRESSION_INTEGER:
kono
parents:
diff changeset
2811 case Expression::EXPRESSION_FLOAT:
kono
parents:
diff changeset
2812 case Expression::EXPRESSION_COMPLEX:
kono
parents:
diff changeset
2813 case Expression::EXPRESSION_NIL:
kono
parents:
diff changeset
2814 case Expression::EXPRESSION_IOTA:
kono
parents:
diff changeset
2815 return;
kono
parents:
diff changeset
2816
kono
parents:
diff changeset
2817 default:
kono
parents:
diff changeset
2818 break;
kono
parents:
diff changeset
2819 }
kono
parents:
diff changeset
2820 }
kono
parents:
diff changeset
2821
kono
parents:
diff changeset
2822 Node::Escape_state* src_state = src->state(this->context_, NULL);
kono
parents:
diff changeset
2823 if (src_state->flood_id == this->context_->flood_id())
kono
parents:
diff changeset
2824 {
kono
parents:
diff changeset
2825 // Esclevels are vectors, do not compare as integers,
kono
parents:
diff changeset
2826 // and must use "min" of old and new to guarantee
kono
parents:
diff changeset
2827 // convergence.
kono
parents:
diff changeset
2828 level = level.min(src_state->level);
kono
parents:
diff changeset
2829 if (level == src_state->level)
kono
parents:
diff changeset
2830 {
kono
parents:
diff changeset
2831 // Have we been here already with an extraloopdepth,
kono
parents:
diff changeset
2832 // or is the extraloopdepth provided no improvement on
kono
parents:
diff changeset
2833 // what's already been seen?
kono
parents:
diff changeset
2834 if (src_state->max_extra_loop_depth >= extra_loop_depth
kono
parents:
diff changeset
2835 || src_state->loop_depth >= extra_loop_depth)
kono
parents:
diff changeset
2836 return;
kono
parents:
diff changeset
2837 src_state->max_extra_loop_depth = extra_loop_depth;
kono
parents:
diff changeset
2838 }
kono
parents:
diff changeset
2839 }
kono
parents:
diff changeset
2840 else
kono
parents:
diff changeset
2841 src_state->max_extra_loop_depth = -1;
kono
parents:
diff changeset
2842
kono
parents:
diff changeset
2843 src_state->flood_id = this->context_->flood_id();
kono
parents:
diff changeset
2844 src_state->level = level;
kono
parents:
diff changeset
2845 int mod_loop_depth = std::max(extra_loop_depth, src_state->loop_depth);
kono
parents:
diff changeset
2846
kono
parents:
diff changeset
2847 Gogo* gogo = this->context_->gogo();
kono
parents:
diff changeset
2848 int debug_level = gogo->debug_escape_level();
kono
parents:
diff changeset
2849 if (debug_level > 1)
kono
parents:
diff changeset
2850 go_inform(Linemap::unknown_location(),
kono
parents:
diff changeset
2851 "escwalk: level:{%d %d} depth:%d "
kono
parents:
diff changeset
2852 "op=%s %s(%s) "
kono
parents:
diff changeset
2853 "scope:%s[%d] "
kono
parents:
diff changeset
2854 "extraloopdepth=%d",
kono
parents:
diff changeset
2855 level.value(), level.suffix_value(), this->context_->pdepth(),
kono
parents:
diff changeset
2856 src->op_format().c_str(),
kono
parents:
diff changeset
2857 src->ast_format(gogo).c_str(),
kono
parents:
diff changeset
2858 src->details().c_str(),
kono
parents:
diff changeset
2859 debug_function_name(src_state->fn).c_str(),
kono
parents:
diff changeset
2860 src_state->loop_depth,
kono
parents:
diff changeset
2861 extra_loop_depth);
kono
parents:
diff changeset
2862
kono
parents:
diff changeset
2863 this->context_->increase_pdepth();
kono
parents:
diff changeset
2864
kono
parents:
diff changeset
2865 // Input parameter flowing into output parameter?
kono
parents:
diff changeset
2866 Named_object* src_no = NULL;
kono
parents:
diff changeset
2867 if (src->expr() != NULL && src->expr()->var_expression() != NULL)
kono
parents:
diff changeset
2868 src_no = src->expr()->var_expression()->named_object();
kono
parents:
diff changeset
2869 else
kono
parents:
diff changeset
2870 src_no = src->object();
kono
parents:
diff changeset
2871 bool src_is_param = (src_no != NULL
kono
parents:
diff changeset
2872 && src_no->is_variable()
kono
parents:
diff changeset
2873 && src_no->var_value()->is_parameter());
kono
parents:
diff changeset
2874
kono
parents:
diff changeset
2875 Named_object* dst_no = NULL;
kono
parents:
diff changeset
2876 if (dst->expr() != NULL && dst->expr()->var_expression() != NULL)
kono
parents:
diff changeset
2877 dst_no = dst->expr()->var_expression()->named_object();
kono
parents:
diff changeset
2878 else
kono
parents:
diff changeset
2879 dst_no = dst->object();
kono
parents:
diff changeset
2880 bool dst_is_result = dst_no != NULL && dst_no->is_result_variable();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2881 Node::Escape_state* dst_state = dst->state(this->context_, NULL);
111
kono
parents:
diff changeset
2882
kono
parents:
diff changeset
2883 if (src_is_param
kono
parents:
diff changeset
2884 && dst_is_result
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2885 && src_state->fn == dst_state->fn
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2886 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP)
111
kono
parents:
diff changeset
2887 && dst->encoding() != Node::ESCAPE_HEAP)
kono
parents:
diff changeset
2888 {
kono
parents:
diff changeset
2889 // This case handles:
kono
parents:
diff changeset
2890 // 1. return in
kono
parents:
diff changeset
2891 // 2. return &in
kono
parents:
diff changeset
2892 // 3. tmp := in; return &tmp
kono
parents:
diff changeset
2893 // 4. return *in
kono
parents:
diff changeset
2894 if (debug_level != 0)
kono
parents:
diff changeset
2895 {
kono
parents:
diff changeset
2896 if (debug_level == 1)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2897 go_inform(src->definition_location(),
111
kono
parents:
diff changeset
2898 "leaking param: %s to result %s level=%d",
kono
parents:
diff changeset
2899 src->ast_format(gogo).c_str(),
kono
parents:
diff changeset
2900 dst->ast_format(gogo).c_str(),
kono
parents:
diff changeset
2901 level.value());
kono
parents:
diff changeset
2902 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2903 go_inform(src->definition_location(),
111
kono
parents:
diff changeset
2904 "leaking param: %s to result %s level={%d %d}",
kono
parents:
diff changeset
2905 src->ast_format(gogo).c_str(),
kono
parents:
diff changeset
2906 dst->ast_format(gogo).c_str(),
kono
parents:
diff changeset
2907 level.value(), level.suffix_value());
kono
parents:
diff changeset
2908 }
kono
parents:
diff changeset
2909
kono
parents:
diff changeset
2910 if ((src->encoding() & ESCAPE_MASK) != Node::ESCAPE_RETURN)
kono
parents:
diff changeset
2911 {
kono
parents:
diff changeset
2912 int enc =
kono
parents:
diff changeset
2913 Node::ESCAPE_RETURN | (src->encoding() & ESCAPE_CONTENT_ESCAPES);
kono
parents:
diff changeset
2914 src->set_encoding(enc);
kono
parents:
diff changeset
2915 }
kono
parents:
diff changeset
2916
kono
parents:
diff changeset
2917 int enc = Node::note_inout_flows(src->encoding(),
kono
parents:
diff changeset
2918 dst_no->result_var_value()->index(),
kono
parents:
diff changeset
2919 level);
kono
parents:
diff changeset
2920 src->set_encoding(enc);
kono
parents:
diff changeset
2921
kono
parents:
diff changeset
2922 // In gc/esc.go:escwalkBody, this is a goto to the label for recursively
kono
parents:
diff changeset
2923 // flooding the connection graph. Inlined here for convenience.
kono
parents:
diff changeset
2924 level = level.copy();
kono
parents:
diff changeset
2925 for (std::set<Node*>::const_iterator p = src_state->flows.begin();
kono
parents:
diff changeset
2926 p != src_state->flows.end();
kono
parents:
diff changeset
2927 ++p)
kono
parents:
diff changeset
2928 this->flood(level, dst, *p, extra_loop_depth);
kono
parents:
diff changeset
2929 return;
kono
parents:
diff changeset
2930 }
kono
parents:
diff changeset
2931
kono
parents:
diff changeset
2932 // If parameter content escape to heap, set ESCAPE_CONTENT_ESCAPES.
kono
parents:
diff changeset
2933 // Note minor confusion around escape from pointer-to-struct vs
kono
parents:
diff changeset
2934 // escape from struct.
kono
parents:
diff changeset
2935 if (src_is_param
kono
parents:
diff changeset
2936 && dst->encoding() == Node::ESCAPE_HEAP
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2937 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP)
111
kono
parents:
diff changeset
2938 && level.value() > 0)
kono
parents:
diff changeset
2939 {
kono
parents:
diff changeset
2940 int enc =
kono
parents:
diff changeset
2941 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES),
kono
parents:
diff changeset
2942 Node::ESCAPE_NONE);
kono
parents:
diff changeset
2943 src->set_encoding(enc);
kono
parents:
diff changeset
2944 if (debug_level != 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2945 go_inform(src->definition_location(), "mark escaped content: %s",
111
kono
parents:
diff changeset
2946 src->ast_format(gogo).c_str());
kono
parents:
diff changeset
2947 }
kono
parents:
diff changeset
2948
kono
parents:
diff changeset
2949 // A src object leaks if its value or address is assigned to a dst object
kono
parents:
diff changeset
2950 // in a different scope (at a different loop depth).
kono
parents:
diff changeset
2951 bool src_leaks = (level.value() <= 0
kono
parents:
diff changeset
2952 && level.suffix_value() <= 0
kono
parents:
diff changeset
2953 && dst_state->loop_depth < mod_loop_depth);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2954 src_leaks = src_leaks || (level.value() <= 0
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2955 && (dst->encoding() & ESCAPE_MASK) == Node::ESCAPE_HEAP);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2956 // old src encoding, used to prevent duplicate error messages
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2957 int osrcesc = src->encoding();
111
kono
parents:
diff changeset
2958
kono
parents:
diff changeset
2959 if (src_is_param
kono
parents:
diff changeset
2960 && (src_leaks || dst_state->loop_depth < 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2961 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP))
111
kono
parents:
diff changeset
2962 {
kono
parents:
diff changeset
2963 if (level.suffix_value() > 0)
kono
parents:
diff changeset
2964 {
kono
parents:
diff changeset
2965 int enc =
kono
parents:
diff changeset
2966 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES),
kono
parents:
diff changeset
2967 Node::ESCAPE_NONE);
kono
parents:
diff changeset
2968 src->set_encoding(enc);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2969 if (debug_level != 0 && osrcesc != src->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2970 go_inform(src->definition_location(), "leaking param content: %s",
111
kono
parents:
diff changeset
2971 src->ast_format(gogo).c_str());
kono
parents:
diff changeset
2972 }
kono
parents:
diff changeset
2973 else
kono
parents:
diff changeset
2974 {
kono
parents:
diff changeset
2975 if (debug_level != 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2976 go_inform(src->definition_location(), "leaking param: %s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2977 src->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2978 src->set_encoding(Node::ESCAPE_HEAP);
111
kono
parents:
diff changeset
2979 }
kono
parents:
diff changeset
2980 }
kono
parents:
diff changeset
2981 else if (src->expr() != NULL)
kono
parents:
diff changeset
2982 {
kono
parents:
diff changeset
2983 Expression* e = src->expr();
kono
parents:
diff changeset
2984 if (e->enclosed_var_expression() != NULL)
kono
parents:
diff changeset
2985 {
kono
parents:
diff changeset
2986 if (src_leaks && debug_level != 0)
kono
parents:
diff changeset
2987 go_inform(src->location(), "leaking closure reference %s",
kono
parents:
diff changeset
2988 src->ast_format(gogo).c_str());
kono
parents:
diff changeset
2989
kono
parents:
diff changeset
2990 Node* enclosed_node =
kono
parents:
diff changeset
2991 Node::make_node(e->enclosed_var_expression()->variable());
kono
parents:
diff changeset
2992 this->flood(level, dst, enclosed_node, -1);
kono
parents:
diff changeset
2993 }
kono
parents:
diff changeset
2994 else if (e->heap_expression() != NULL
kono
parents:
diff changeset
2995 || (e->unary_expression() != NULL
kono
parents:
diff changeset
2996 && e->unary_expression()->op() == OPERATOR_AND))
kono
parents:
diff changeset
2997 {
kono
parents:
diff changeset
2998 // Pointer literals and address-of expressions.
kono
parents:
diff changeset
2999 Expression* underlying;
kono
parents:
diff changeset
3000 if (e->heap_expression())
kono
parents:
diff changeset
3001 underlying = e->heap_expression()->expr();
kono
parents:
diff changeset
3002 else
kono
parents:
diff changeset
3003 underlying = e->unary_expression()->operand();
kono
parents:
diff changeset
3004 Node* underlying_node = Node::make_node(underlying);
kono
parents:
diff changeset
3005
kono
parents:
diff changeset
3006 // If the address leaks, the underyling object must be moved
kono
parents:
diff changeset
3007 // to the heap.
kono
parents:
diff changeset
3008 underlying->address_taken(src_leaks);
kono
parents:
diff changeset
3009 if (src_leaks)
kono
parents:
diff changeset
3010 {
kono
parents:
diff changeset
3011 src->set_encoding(Node::ESCAPE_HEAP);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3012 if (osrcesc != src->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3013 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3014 move_to_heap(gogo, underlying);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3015 if (debug_level > 1)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3016 go_inform(src->location(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3017 "%s escapes to heap, level={%d %d}, "
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3018 "dst.eld=%d, src.eld=%d",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3019 src->ast_format(gogo).c_str(), level.value(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3020 level.suffix_value(), dst_state->loop_depth,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3021 mod_loop_depth);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3022 else if (debug_level > 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3023 go_inform(src->location(), "%s escapes to heap",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3024 src->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3025 }
111
kono
parents:
diff changeset
3026
kono
parents:
diff changeset
3027 this->flood(level.decrease(), dst,
kono
parents:
diff changeset
3028 underlying_node, mod_loop_depth);
kono
parents:
diff changeset
3029 extra_loop_depth = mod_loop_depth;
kono
parents:
diff changeset
3030 }
kono
parents:
diff changeset
3031 else
kono
parents:
diff changeset
3032 {
kono
parents:
diff changeset
3033 // Decrease the level each time we take the address of the object.
kono
parents:
diff changeset
3034 this->flood(level.decrease(), dst, underlying_node, -1);
kono
parents:
diff changeset
3035 }
kono
parents:
diff changeset
3036 }
kono
parents:
diff changeset
3037 else if (e->slice_literal() != NULL)
kono
parents:
diff changeset
3038 {
kono
parents:
diff changeset
3039 Slice_construction_expression* slice = e->slice_literal();
kono
parents:
diff changeset
3040 if (slice->vals() != NULL)
kono
parents:
diff changeset
3041 {
kono
parents:
diff changeset
3042 for (Expression_list::const_iterator p = slice->vals()->begin();
kono
parents:
diff changeset
3043 p != slice->vals()->end();
kono
parents:
diff changeset
3044 ++p)
kono
parents:
diff changeset
3045 {
kono
parents:
diff changeset
3046 if ((*p) != NULL)
kono
parents:
diff changeset
3047 this->flood(level.decrease(), dst, Node::make_node(*p), -1);
kono
parents:
diff changeset
3048 }
kono
parents:
diff changeset
3049 }
kono
parents:
diff changeset
3050 if (src_leaks)
kono
parents:
diff changeset
3051 {
kono
parents:
diff changeset
3052 src->set_encoding(Node::ESCAPE_HEAP);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3053 if (debug_level != 0 && osrcesc != src->encoding())
111
kono
parents:
diff changeset
3054 go_inform(src->location(), "%s escapes to heap",
kono
parents:
diff changeset
3055 src->ast_format(gogo).c_str());
kono
parents:
diff changeset
3056 extra_loop_depth = mod_loop_depth;
kono
parents:
diff changeset
3057 }
kono
parents:
diff changeset
3058 }
kono
parents:
diff changeset
3059 else if (e->call_expression() != NULL)
kono
parents:
diff changeset
3060 {
kono
parents:
diff changeset
3061 Call_expression* call = e->call_expression();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3062 if (call->is_builtin())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3063 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3064 Builtin_call_expression* bce = call->builtin_call_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3065 if (bce->code() == Builtin_call_expression::BUILTIN_APPEND)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3066 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3067 // Propagate escape information to appendee.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3068 Expression* appendee = call->args()->front();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3069 this->flood(level, dst, Node::make_node(appendee), -1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3070 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3071 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3072 else if (call->fn()->func_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3073 && call->fn()->func_expression()->is_runtime_function())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3074 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3075 switch (call->fn()->func_expression()->runtime_code())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3076 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3077 case Runtime::MAKECHAN:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3078 case Runtime::MAKECHAN64:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3079 case Runtime::MAKEMAP:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3080 case Runtime::MAKESLICE:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3081 case Runtime::MAKESLICE64:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3082 if (src_leaks)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3083 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3084 src->set_encoding(Node::ESCAPE_HEAP);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3085 if (debug_level != 0 && osrcesc != src->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3086 go_inform(src->location(), "%s escapes to heap",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3087 src->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3088 extra_loop_depth = mod_loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3089 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3090 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3091
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3092 default:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3093 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3094 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3095 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3096 else if (src_state->retvals.size() > 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3097 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3098 // In this case a link went directly to a call, but should really go
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3099 // to the dummy .outN outputs that were created for the call that
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3100 // themselves link to the inputs with levels adjusted.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3101 // See e.g. #10466.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3102 // This can only happen with functions returning a single result.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3103 go_assert(src_state->retvals.size() == 1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3104 if (debug_level > 2)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3105 go_inform(src->location(), "[%d] dst %s escwalk replace src: %s with %s",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3106 this->context_->loop_depth(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3107 dst->ast_format(gogo).c_str(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3108 src->ast_format(gogo).c_str(),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3109 src_state->retvals[0]->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3110 src = src_state->retvals[0];
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3111 src_state = src->state(this->context_, NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3112 }
111
kono
parents:
diff changeset
3113 }
kono
parents:
diff changeset
3114 else if (e->allocation_expression() != NULL && src_leaks)
kono
parents:
diff changeset
3115 {
kono
parents:
diff changeset
3116 // Calls to Runtime::NEW get lowered into an allocation expression.
kono
parents:
diff changeset
3117 src->set_encoding(Node::ESCAPE_HEAP);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3118 if (debug_level != 0 && osrcesc != src->encoding())
111
kono
parents:
diff changeset
3119 go_inform(src->location(), "%s escapes to heap",
kono
parents:
diff changeset
3120 src->ast_format(gogo).c_str());
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3121 extra_loop_depth = mod_loop_depth;
111
kono
parents:
diff changeset
3122 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3123 else if ((e->map_literal() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3124 || e->string_concat_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3125 || (e->func_expression() != NULL && e->func_expression()->closure() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3126 || e->bound_method_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3127 && src_leaks)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3128 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3129 src->set_encoding(Node::ESCAPE_HEAP);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3130 if (debug_level != 0 && osrcesc != src->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3131 go_inform(src->location(), "%s escapes to heap",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3132 src->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3133 extra_loop_depth = mod_loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3134 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3135 else if (e->conversion_expression() != NULL && src_leaks)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3136 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3137 Type_conversion_expression* tce = e->conversion_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3138 Type* ft = tce->expr()->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3139 Type* tt = tce->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3140 if ((ft->is_string_type() && tt->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3141 || (ft->is_slice_type() && tt->is_string_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3142 || (ft->integer_type() != NULL && tt->is_string_type()))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3143 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3144 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3145 src->set_encoding(Node::ESCAPE_HEAP);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3146 if (debug_level != 0 && osrcesc != src->encoding())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3147 go_inform(src->location(), "%s escapes to heap",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3148 src->ast_format(gogo).c_str());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3149 extra_loop_depth = mod_loop_depth;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3150 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3151 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3152 else if (e->array_index_expression() != NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3153 && !e->array_index_expression()->array()->type()->is_slice_type())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3154 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3155 Array_index_expression* aie = e->array_index_expression();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3156 if (aie->end() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3157 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3158 // Slicing an array.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3159 // Flow its implicit address-of node to DST.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3160 this->flood(level, dst, src->child(), -1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3161 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3162 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3163 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3164 // Indexing an array.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3165 // An array element flowing to DST behaves like the array
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3166 // flowing to DST.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3167 Expression* underlying = e->array_index_expression()->array();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3168 Node* underlying_node = Node::make_node(underlying);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3169 this->flood(level, dst, underlying_node, -1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3170 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3171 }
111
kono
parents:
diff changeset
3172 else if ((e->field_reference_expression() != NULL
kono
parents:
diff changeset
3173 && e->field_reference_expression()->expr()->unary_expression() == NULL)
kono
parents:
diff changeset
3174 || e->type_guard_expression() != NULL
kono
parents:
diff changeset
3175 || (e->array_index_expression() != NULL
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3176 && e->array_index_expression()->end() != NULL)
111
kono
parents:
diff changeset
3177 || (e->string_index_expression() != NULL
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3178 && e->type()->is_string_type()))
111
kono
parents:
diff changeset
3179 {
kono
parents:
diff changeset
3180 Expression* underlying;
kono
parents:
diff changeset
3181 if (e->field_reference_expression() != NULL)
kono
parents:
diff changeset
3182 underlying = e->field_reference_expression()->expr();
kono
parents:
diff changeset
3183 else if (e->type_guard_expression() != NULL)
kono
parents:
diff changeset
3184 underlying = e->type_guard_expression()->expr();
kono
parents:
diff changeset
3185 else if (e->array_index_expression() != NULL)
kono
parents:
diff changeset
3186 underlying = e->array_index_expression()->array();
kono
parents:
diff changeset
3187 else
kono
parents:
diff changeset
3188 underlying = e->string_index_expression()->string();
kono
parents:
diff changeset
3189
kono
parents:
diff changeset
3190 Node* underlying_node = Node::make_node(underlying);
kono
parents:
diff changeset
3191 this->flood(level, dst, underlying_node, -1);
kono
parents:
diff changeset
3192 }
kono
parents:
diff changeset
3193 else if ((e->field_reference_expression() != NULL
kono
parents:
diff changeset
3194 && e->field_reference_expression()->expr()->unary_expression() != NULL)
kono
parents:
diff changeset
3195 || e->array_index_expression() != NULL
kono
parents:
diff changeset
3196 || e->map_index_expression() != NULL
kono
parents:
diff changeset
3197 || (e->unary_expression() != NULL
kono
parents:
diff changeset
3198 && e->unary_expression()->op() == OPERATOR_MULT))
kono
parents:
diff changeset
3199 {
kono
parents:
diff changeset
3200 Expression* underlying;
kono
parents:
diff changeset
3201 if (e->field_reference_expression() != NULL)
kono
parents:
diff changeset
3202 {
kono
parents:
diff changeset
3203 underlying = e->field_reference_expression()->expr();
kono
parents:
diff changeset
3204 underlying = underlying->unary_expression()->operand();
kono
parents:
diff changeset
3205 }
kono
parents:
diff changeset
3206 else if (e->array_index_expression() != NULL)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3207 underlying = e->array_index_expression()->array();
111
kono
parents:
diff changeset
3208 else if (e->map_index_expression() != NULL)
kono
parents:
diff changeset
3209 underlying = e->map_index_expression()->map();
kono
parents:
diff changeset
3210 else
kono
parents:
diff changeset
3211 underlying = e->unary_expression()->operand();
kono
parents:
diff changeset
3212
kono
parents:
diff changeset
3213 // Increase the level for a dereference.
kono
parents:
diff changeset
3214 Node* underlying_node = Node::make_node(underlying);
kono
parents:
diff changeset
3215 this->flood(level.increase(), dst, underlying_node, -1);
kono
parents:
diff changeset
3216 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3217 else if (e->temporary_reference_expression() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3218 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3219 Statement* t = e->temporary_reference_expression()->statement();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3220 this->flood(level, dst, Node::make_node(t), -1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3221 }
111
kono
parents:
diff changeset
3222 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3223 else if (src->is_indirect())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3224 // Increase the level for a dereference.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3225 this->flood(level.increase(), dst, src->child(), -1);
111
kono
parents:
diff changeset
3226
kono
parents:
diff changeset
3227 level = level.copy();
kono
parents:
diff changeset
3228 for (std::set<Node*>::const_iterator p = src_state->flows.begin();
kono
parents:
diff changeset
3229 p != src_state->flows.end();
kono
parents:
diff changeset
3230 ++p)
kono
parents:
diff changeset
3231 this->flood(level, dst, *p, extra_loop_depth);
kono
parents:
diff changeset
3232
kono
parents:
diff changeset
3233 this->context_->decrease_pdepth();
kono
parents:
diff changeset
3234 }
kono
parents:
diff changeset
3235
kono
parents:
diff changeset
3236 // Propagate escape information across the nodes modeled in this Analysis_set.
kono
parents:
diff changeset
3237 // This is an implementation of gc/esc.go:escflood.
kono
parents:
diff changeset
3238
kono
parents:
diff changeset
3239 void
kono
parents:
diff changeset
3240 Gogo::propagate_escape(Escape_context* context, Node* dst)
kono
parents:
diff changeset
3241 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3242 if (dst->object() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3243 && (dst->expr() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3244 || (dst->expr()->var_expression() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3245 && dst->expr()->enclosed_var_expression() == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3246 && dst->expr()->func_expression() == NULL)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3247 return;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3248
111
kono
parents:
diff changeset
3249 Node::Escape_state* state = dst->state(context, NULL);
kono
parents:
diff changeset
3250 Gogo* gogo = context->gogo();
kono
parents:
diff changeset
3251 if (gogo->debug_escape_level() > 1)
kono
parents:
diff changeset
3252 go_inform(Linemap::unknown_location(), "escflood:%d: dst %s scope:%s[%d]",
kono
parents:
diff changeset
3253 context->flood_id(), dst->ast_format(gogo).c_str(),
kono
parents:
diff changeset
3254 debug_function_name(state->fn).c_str(),
kono
parents:
diff changeset
3255 state->loop_depth);
kono
parents:
diff changeset
3256
kono
parents:
diff changeset
3257 Escape_analysis_flood eaf(context);
kono
parents:
diff changeset
3258 for (std::set<Node*>::const_iterator p = state->flows.begin();
kono
parents:
diff changeset
3259 p != state->flows.end();
kono
parents:
diff changeset
3260 ++p)
kono
parents:
diff changeset
3261 {
kono
parents:
diff changeset
3262 context->increase_flood_id();
kono
parents:
diff changeset
3263 eaf.flood(Level::From(0), dst, *p, -1);
kono
parents:
diff changeset
3264 }
kono
parents:
diff changeset
3265 }
kono
parents:
diff changeset
3266
kono
parents:
diff changeset
3267 class Escape_analysis_tag
kono
parents:
diff changeset
3268 {
kono
parents:
diff changeset
3269 public:
kono
parents:
diff changeset
3270 Escape_analysis_tag(Escape_context* context)
kono
parents:
diff changeset
3271 : context_(context)
kono
parents:
diff changeset
3272 { }
kono
parents:
diff changeset
3273
kono
parents:
diff changeset
3274 // Add notes to the function's type about the escape information of its
kono
parents:
diff changeset
3275 // input parameters.
kono
parents:
diff changeset
3276 void
kono
parents:
diff changeset
3277 tag(Named_object* fn);
kono
parents:
diff changeset
3278
kono
parents:
diff changeset
3279 private:
kono
parents:
diff changeset
3280 Escape_context* context_;
kono
parents:
diff changeset
3281 };
kono
parents:
diff changeset
3282
kono
parents:
diff changeset
3283 void
kono
parents:
diff changeset
3284 Escape_analysis_tag::tag(Named_object* fn)
kono
parents:
diff changeset
3285 {
kono
parents:
diff changeset
3286 // External functions are assumed unsafe
kono
parents:
diff changeset
3287 // unless //go:noescape is given before the declaration.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3288 if (fn->package() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3289 return;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3290
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3291 if (fn->is_function_declaration())
111
kono
parents:
diff changeset
3292 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3293 Function_declaration* fdcl = fn->func_declaration_value();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3294 if ((fdcl->pragmas() & GOPRAGMA_NOESCAPE) != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3295 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3296 Function_type* fntype = fdcl->type();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3297 if (fntype->parameters() != NULL)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3298 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3299 const Typed_identifier_list* til = fntype->parameters();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3300 int i = 0;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3301 for (Typed_identifier_list::const_iterator p = til->begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3302 p != til->end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3303 ++p, ++i)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3304 if (p->type()->has_pointer())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3305 fntype->add_parameter_note(i, Node::ESCAPE_NONE);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3306 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3307 }
111
kono
parents:
diff changeset
3308 }
kono
parents:
diff changeset
3309
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3310 if (!fn->is_function())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3311 return;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3312
111
kono
parents:
diff changeset
3313 Function_type* fntype = fn->func_value()->type();
kono
parents:
diff changeset
3314 Bindings* bindings = fn->func_value()->block()->bindings();
kono
parents:
diff changeset
3315
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3316 if (fntype->is_method())
111
kono
parents:
diff changeset
3317 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3318 if (fntype->receiver()->name().empty()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3319 || Gogo::is_sink_name(fntype->receiver()->name()))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3320 // Unnamed receiver is not used in the function body, does not escape.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3321 fntype->add_receiver_note(Node::ESCAPE_NONE);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3322 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3323 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3324 Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3325 go_assert(rcvr_no != NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3326 Node* rcvr_node = Node::make_node(rcvr_no);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3327 switch ((rcvr_node->encoding() & ESCAPE_MASK))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3328 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3329 case Node::ESCAPE_NONE: // not touched by flood
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3330 case Node::ESCAPE_RETURN:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3331 if (fntype->receiver()->type()->has_pointer())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3332 // Don't bother tagging for scalars.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3333 fntype->add_receiver_note(rcvr_node->encoding());
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3334 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3335
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3336 case Node::ESCAPE_HEAP: // flooded, moved to heap.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3337 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3338
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3339 default:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3340 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3341 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3342 }
111
kono
parents:
diff changeset
3343 }
kono
parents:
diff changeset
3344
kono
parents:
diff changeset
3345 int i = 0;
kono
parents:
diff changeset
3346 if (fntype->parameters() != NULL)
kono
parents:
diff changeset
3347 {
kono
parents:
diff changeset
3348 const Typed_identifier_list* til = fntype->parameters();
kono
parents:
diff changeset
3349 for (Typed_identifier_list::const_iterator p = til->begin();
kono
parents:
diff changeset
3350 p != til->end();
kono
parents:
diff changeset
3351 ++p, ++i)
kono
parents:
diff changeset
3352 {
kono
parents:
diff changeset
3353 if (p->name().empty() || Gogo::is_sink_name(p->name()))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3354 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3355 // Parameter not used in the function body, does not escape.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3356 if (p->type()->has_pointer())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3357 fntype->add_parameter_note(i, Node::ESCAPE_NONE);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3358 continue;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3359 }
111
kono
parents:
diff changeset
3360
kono
parents:
diff changeset
3361 Named_object* param_no = bindings->lookup(p->name());
kono
parents:
diff changeset
3362 go_assert(param_no != NULL);
kono
parents:
diff changeset
3363 Node* param_node = Node::make_node(param_no);
kono
parents:
diff changeset
3364 switch ((param_node->encoding() & ESCAPE_MASK))
kono
parents:
diff changeset
3365 {
kono
parents:
diff changeset
3366 case Node::ESCAPE_NONE: // not touched by flood
kono
parents:
diff changeset
3367 case Node::ESCAPE_RETURN:
kono
parents:
diff changeset
3368 if (p->type()->has_pointer())
kono
parents:
diff changeset
3369 // Don't bother tagging for scalars.
kono
parents:
diff changeset
3370 fntype->add_parameter_note(i, param_node->encoding());
kono
parents:
diff changeset
3371 break;
kono
parents:
diff changeset
3372
kono
parents:
diff changeset
3373 case Node::ESCAPE_HEAP: // flooded, moved to heap.
kono
parents:
diff changeset
3374 break;
kono
parents:
diff changeset
3375
kono
parents:
diff changeset
3376 default:
kono
parents:
diff changeset
3377 break;
kono
parents:
diff changeset
3378 }
kono
parents:
diff changeset
3379 }
kono
parents:
diff changeset
3380 }
kono
parents:
diff changeset
3381 fntype->set_is_tagged();
kono
parents:
diff changeset
3382 }
kono
parents:
diff changeset
3383
kono
parents:
diff changeset
3384 // Tag each top-level function with escape information that will be used to
kono
parents:
diff changeset
3385 // retain analysis results across imports.
kono
parents:
diff changeset
3386
kono
parents:
diff changeset
3387 void
kono
parents:
diff changeset
3388 Gogo::tag_function(Escape_context* context, Named_object* fn)
kono
parents:
diff changeset
3389 {
kono
parents:
diff changeset
3390 Escape_analysis_tag eat(context);
kono
parents:
diff changeset
3391 eat.tag(fn);
kono
parents:
diff changeset
3392 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3393
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3394 // Reclaim memory of escape analysis Nodes.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3395
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3396 void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3397 Gogo::reclaim_escape_nodes()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3398 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3399 Node::reclaim_nodes();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3400 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3401
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3402 void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3403 Node::reclaim_nodes()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3404 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3405 for (std::map<Named_object*, Node*>::iterator p = Node::objects.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3406 p != Node::objects.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3407 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3408 delete p->second;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3409 Node::objects.clear();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3410
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3411 for (std::map<Expression*, Node*>::iterator p = Node::expressions.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3412 p != Node::expressions.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3413 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3414 delete p->second;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3415 Node::expressions.clear();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3416
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3417 for (std::map<Statement*, Node*>::iterator p = Node::statements.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3418 p != Node::statements.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3419 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3420 delete p->second;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3421 Node::statements.clear();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3422
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3423 for (std::vector<Node*>::iterator p = Node::indirects.begin();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3424 p != Node::indirects.end();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3425 ++p)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3426 delete *p;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3427 Node::indirects.clear();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3428 }