Mercurial > hg > CbC > CbC_gcc
comparison 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 |
comparison
equal
deleted
inserted
replaced
111:04ced10e8804 | 131:84e7813d76e9 |
---|---|
13 #include "gogo.h" | 13 #include "gogo.h" |
14 #include "types.h" | 14 #include "types.h" |
15 #include "expressions.h" | 15 #include "expressions.h" |
16 #include "statements.h" | 16 #include "statements.h" |
17 #include "escape.h" | 17 #include "escape.h" |
18 #include "lex.h" | |
18 #include "ast-dump.h" | 19 #include "ast-dump.h" |
19 #include "go-optimize.h" | 20 #include "go-optimize.h" |
20 #include "go-diagnostics.h" | 21 #include "go-diagnostics.h" |
22 #include "go-sha1.h" | |
21 | 23 |
22 // class Node. | 24 // class Node. |
23 | 25 |
24 // Return the node's type, if it makes sense for it to have one. | 26 // Return the node's type, if it makes sense for it to have one. |
25 | 27 |
32 else if (this->object() != NULL | 34 else if (this->object() != NULL |
33 && this->object()->is_function()) | 35 && this->object()->is_function()) |
34 return this->object()->func_value()->type(); | 36 return this->object()->func_value()->type(); |
35 else if (this->expr() != NULL) | 37 else if (this->expr() != NULL) |
36 return this->expr()->type(); | 38 return this->expr()->type(); |
39 else if (this->is_indirect()) | |
40 { | |
41 if (this->child()->type()->deref()->is_void_type()) | |
42 // This is a void*. The referred type can be actually any type, | |
43 // which may also be pointer. We model it as another void*, so | |
44 // we don't lose pointer-ness. | |
45 return this->child()->type(); | |
46 else if (this->child()->type()->is_slice_type()) | |
47 // We model "indirect" of a slice as dereferencing its pointer | |
48 // field (to get element). Use element type here. | |
49 return this->child()->type()->array_type()->element_type(); | |
50 else if (this->child()->type()->is_string_type()) | |
51 return Type::lookup_integer_type("uint8"); | |
52 else | |
53 return this->child()->type()->deref(); | |
54 } | |
55 else if (this->statement() != NULL | |
56 && this->statement()->temporary_statement() != NULL) | |
57 return this->statement()->temporary_statement()->type(); | |
37 else | 58 else |
38 return NULL; | 59 return NULL; |
39 } | 60 } |
40 | 61 |
41 // A helper for reporting; return this node's location. | 62 // A helper for reporting; return this node's location. |
47 return this->object()->location(); | 68 return this->object()->location(); |
48 else if (this->expr() != NULL) | 69 else if (this->expr() != NULL) |
49 return this->expr()->location(); | 70 return this->expr()->location(); |
50 else if (this->statement() != NULL) | 71 else if (this->statement() != NULL) |
51 return this->statement()->location(); | 72 return this->statement()->location(); |
73 else if (this->is_indirect()) | |
74 return this->child()->location(); | |
52 else | 75 else |
53 return Linemap::unknown_location(); | 76 return Linemap::unknown_location(); |
77 } | |
78 | |
79 // A helper for reporting; return the location where the underlying | |
80 // object is defined. | |
81 | |
82 Location | |
83 Node::definition_location() const | |
84 { | |
85 if (this->object() != NULL && !this->object()->is_sink()) | |
86 { | |
87 Named_object* no = this->object(); | |
88 if (no->is_variable() || no->is_result_variable()) | |
89 return no->location(); | |
90 } | |
91 else if (this->expr() != NULL) | |
92 { | |
93 Var_expression* ve = this->expr()->var_expression(); | |
94 if (ve != NULL) | |
95 { | |
96 Named_object* no = ve->named_object(); | |
97 if (no->is_variable() || no->is_result_variable()) | |
98 return no->location(); | |
99 } | |
100 Enclosed_var_expression* eve = this->expr()->enclosed_var_expression(); | |
101 if (eve != NULL) | |
102 { | |
103 Named_object* no = eve->variable(); | |
104 if (no->is_variable() || no->is_result_variable()) | |
105 return no->location(); | |
106 } | |
107 } | |
108 return this->location(); | |
54 } | 109 } |
55 | 110 |
56 // To match the cmd/gc debug output, strip away the packed prefixes on functions | 111 // To match the cmd/gc debug output, strip away the packed prefixes on functions |
57 // and variable/expressions. | 112 // and variable/expressions. |
58 | 113 |
80 else if (this->object() != NULL) | 135 else if (this->object() != NULL) |
81 { | 136 { |
82 Named_object* no = this->object(); | 137 Named_object* no = this->object(); |
83 if (no->is_function() && no->func_value()->enclosing() != NULL) | 138 if (no->is_function() && no->func_value()->enclosing() != NULL) |
84 return "func literal"; | 139 return "func literal"; |
85 ss << no->name(); | 140 ss << no->message_name(); |
86 } | 141 } |
87 else if (this->expr() != NULL) | 142 else if (this->expr() != NULL) |
88 { | 143 { |
89 Expression* e = this->expr(); | 144 Expression* e = this->expr(); |
90 bool is_call = e->call_expression() != NULL; | 145 bool is_call = e->call_expression() != NULL; |
99 return "(func literal)()"; | 154 return "(func literal)()"; |
100 return "func literal"; | 155 return "func literal"; |
101 } | 156 } |
102 Ast_dump_context::dump_to_stream(this->expr(), &ss); | 157 Ast_dump_context::dump_to_stream(this->expr(), &ss); |
103 } | 158 } |
104 else | 159 else if (this->statement() != NULL) |
105 { | 160 { |
106 Statement* s = this->statement(); | 161 Statement* s = this->statement(); |
107 Goto_unnamed_statement* unnamed = s->goto_unnamed_statement(); | 162 Goto_unnamed_statement* unnamed = s->goto_unnamed_statement(); |
108 if (unnamed != NULL) | 163 if (unnamed != NULL) |
109 { | 164 { |
128 default: | 183 default: |
129 break; | 184 break; |
130 } | 185 } |
131 } | 186 } |
132 } | 187 } |
133 Ast_dump_context::dump_to_stream(s, &ss); | 188 Temporary_statement* tmp = s->temporary_statement(); |
134 } | 189 if (tmp != NULL) |
135 | 190 { |
136 return strip_packed_prefix(gogo, ss.str()); | 191 // Temporary's format can never match gc's output, and |
192 // temporaries are inserted differently anyway. We just | |
193 // print something convenient. | |
194 ss << "tmp." << (uintptr_t) tmp; | |
195 if (tmp->init() != NULL) | |
196 { | |
197 ss << " [ = "; | |
198 Ast_dump_context::dump_to_stream(tmp->init(), &ss); | |
199 ss << " ]"; | |
200 } | |
201 } | |
202 else | |
203 Ast_dump_context::dump_to_stream(s, &ss); | |
204 } | |
205 else if (this->is_indirect()) | |
206 return "*(" + this->child()->ast_format(gogo) + ")"; | |
207 | |
208 std::string s = strip_packed_prefix(gogo, ss.str()); | |
209 | |
210 // trim trailing space | |
211 return s.substr(0, s.find_last_not_of(' ') + 1); | |
137 } | 212 } |
138 | 213 |
139 // A helper for debugging; return this node's detailed format string. | 214 // A helper for debugging; return this node's detailed format string. |
140 // This is an implementation of gc's Jconv with obj.FmtShort. | 215 // This is an implementation of gc's Jconv with obj.FmtShort. |
141 | 216 |
142 std::string | 217 std::string |
143 Node::details() const | 218 Node::details() |
144 { | 219 { |
145 std::stringstream details; | 220 std::stringstream details; |
146 | 221 |
147 if (!this->is_sink()) | 222 if (!this->is_sink()) |
148 details << " l(" << Linemap::location_to_line(this->location()) << ")"; | 223 details << " l(" << Linemap::location_to_line(this->location()) << ")"; |
221 | 296 |
222 case Node::ESCAPE_HEAP: | 297 case Node::ESCAPE_HEAP: |
223 details << " esc(h)"; | 298 details << " esc(h)"; |
224 break; | 299 break; |
225 | 300 |
226 case Node::ESCAPE_SCOPE: | |
227 details << " esc(s)"; | |
228 break; | |
229 | |
230 case Node::ESCAPE_NONE: | 301 case Node::ESCAPE_NONE: |
231 details << " esc(no)"; | 302 details << " esc(no)"; |
232 break; | 303 break; |
233 | 304 |
234 case Node::ESCAPE_NEVER: | 305 case Node::ESCAPE_NEVER: |
293 case Runtime::TYPEDSLICECOPY: | 364 case Runtime::TYPEDSLICECOPY: |
294 op << "copy"; | 365 op << "copy"; |
295 break; | 366 break; |
296 | 367 |
297 case Runtime::MAKECHAN: | 368 case Runtime::MAKECHAN: |
369 case Runtime::MAKECHAN64: | |
298 case Runtime::MAKEMAP: | 370 case Runtime::MAKEMAP: |
299 case Runtime::MAKESLICE: | 371 case Runtime::MAKESLICE: |
300 case Runtime::MAKESLICE64: | 372 case Runtime::MAKESLICE64: |
301 op << "make"; | 373 op << "make"; |
302 break; | 374 break; |
346 | 418 |
347 default: | 419 default: |
348 break; | 420 break; |
349 } | 421 } |
350 } | 422 } |
423 if (this->is_indirect()) | |
424 op << "*"; | |
351 return op.str(); | 425 return op.str(); |
352 } | 426 } |
353 | 427 |
354 // Return this node's state, creating it if has not been initialized. | 428 // Return this node's state, creating it if has not been initialized. |
355 | 429 |
376 } | 450 } |
377 go_assert(this->state_ != NULL); | 451 go_assert(this->state_ != NULL); |
378 return this->state_; | 452 return this->state_; |
379 } | 453 } |
380 | 454 |
455 Node::~Node() | |
456 { | |
457 if (this->state_ != NULL) | |
458 { | |
459 if (this->expr() == NULL || this->expr()->var_expression() == NULL) | |
460 // Var expression Node is excluded since it shares state with the | |
461 // underlying var Node. | |
462 delete this->state_; | |
463 } | |
464 } | |
465 | |
466 int | |
467 Node::encoding() | |
468 { | |
469 if (this->expr() != NULL | |
470 && this->expr()->var_expression() != NULL) | |
471 { | |
472 // Get the underlying object's encoding. | |
473 Named_object* no = this->expr()->var_expression()->named_object(); | |
474 int enc = Node::make_node(no)->encoding(); | |
475 this->encoding_ = enc; | |
476 } | |
477 return this->encoding_; | |
478 } | |
479 | |
381 void | 480 void |
382 Node::set_encoding(int enc) | 481 Node::set_encoding(int enc) |
383 { | 482 { |
384 this->encoding_ = enc; | 483 this->encoding_ = enc; |
385 if (this->expr() != NULL | 484 if (this->expr() != NULL) |
386 && this->expr()->var_expression() != NULL) | 485 { |
387 { | 486 if (this->expr()->var_expression() != NULL) |
388 // Set underlying object as well. | 487 { |
389 Named_object* no = this->expr()->var_expression()->named_object(); | 488 // Set underlying object as well. |
390 Node::make_node(no)->set_encoding(enc); | 489 Named_object* no = this->expr()->var_expression()->named_object(); |
490 Node::make_node(no)->set_encoding(enc); | |
491 } | |
492 else if (this->expr()->func_expression() != NULL) | |
493 { | |
494 // Propagate the escape state to the underlying | |
495 // closure (heap expression). | |
496 Expression* closure = this->expr()->func_expression()->closure(); | |
497 if (closure != NULL) | |
498 Node::make_node(closure)->set_encoding(enc); | |
499 } | |
391 } | 500 } |
392 } | 501 } |
393 | 502 |
394 bool | 503 bool |
395 Node::is_big(Escape_context* context) const | 504 Node::is_big(Escape_context* context) const |
424 { | 533 { |
425 // Second argument is length. | 534 // Second argument is length. |
426 Expression_list::iterator p = call->args()->begin(); | 535 Expression_list::iterator p = call->args()->begin(); |
427 ++p; | 536 ++p; |
428 | 537 |
538 Expression* e = *p; | |
539 if (e->temporary_reference_expression() != NULL) | |
540 { | |
541 Temporary_reference_expression* tre = e->temporary_reference_expression(); | |
542 if (tre->statement() != NULL && tre->statement()->init() != NULL) | |
543 e = tre->statement()->init(); | |
544 } | |
545 | |
429 Numeric_constant nc; | 546 Numeric_constant nc; |
430 unsigned long v; | 547 unsigned long v; |
431 if ((*p)->numeric_constant_value(&nc) | 548 if (e->numeric_constant_value(&nc) |
432 && nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_VALID) | 549 && nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_VALID) |
433 big = big || v >= (1 << 16); | 550 big = big || v >= (1 << 16); |
434 } | 551 } |
435 } | 552 } |
436 } | 553 } |
451 } | 568 } |
452 | 569 |
453 std::map<Named_object*, Node*> Node::objects; | 570 std::map<Named_object*, Node*> Node::objects; |
454 std::map<Expression*, Node*> Node::expressions; | 571 std::map<Expression*, Node*> Node::expressions; |
455 std::map<Statement*, Node*> Node::statements; | 572 std::map<Statement*, Node*> Node::statements; |
573 std::vector<Node*> Node::indirects; | |
456 | 574 |
457 // Make a object node or return a cached node for this object. | 575 // Make a object node or return a cached node for this object. |
458 | 576 |
459 Node* | 577 Node* |
460 Node::make_node(Named_object* no) | 578 Node::make_node(Named_object* no) |
494 std::pair<Statement*, Node*> val(s, n); | 612 std::pair<Statement*, Node*> val(s, n); |
495 Node::statements.insert(val); | 613 Node::statements.insert(val); |
496 return n; | 614 return n; |
497 } | 615 } |
498 | 616 |
617 // Make an indirect node with given child. | |
618 | |
619 Node* | |
620 Node::make_indirect_node(Node* child) | |
621 { | |
622 Node* n = new Node(child); | |
623 Node::indirects.push_back(n); | |
624 return n; | |
625 } | |
626 | |
499 // Returns the maximum of an exisiting escape value | 627 // Returns the maximum of an exisiting escape value |
500 // (and its additional parameter flow flags) and a new escape type. | 628 // (and its additional parameter flow flags) and a new escape type. |
501 | 629 |
502 int | 630 int |
503 Node::max_encoding(int e, int etype) | 631 Node::max_encoding(int e, int etype) |
504 { | 632 { |
505 if ((e & ESCAPE_MASK) >= etype) | 633 if ((e & ESCAPE_MASK) > etype) |
506 return e; | 634 return e; |
507 if (etype == Node::ESCAPE_NONE || etype == Node::ESCAPE_RETURN) | 635 if (etype == Node::ESCAPE_NONE || etype == Node::ESCAPE_RETURN) |
508 return (e & ~ESCAPE_MASK) | etype; | 636 return (e & ~ESCAPE_MASK) | etype; |
509 return etype; | 637 return etype; |
510 } | 638 } |
550 sink_(Node::make_node(Named_object::make_sink())), loop_depth_(0), | 678 sink_(Node::make_node(Named_object::make_sink())), loop_depth_(0), |
551 flood_id_(0), pdepth_(0) | 679 flood_id_(0), pdepth_(0) |
552 { | 680 { |
553 // The sink always escapes to heap and strictly lives outside of the | 681 // The sink always escapes to heap and strictly lives outside of the |
554 // current function i.e. loop_depth == -1. | 682 // current function i.e. loop_depth == -1. |
555 this->sink_->set_encoding(Node::ESCAPE_HEAP); | |
556 Node::Escape_state* state = this->sink_->state(this, NULL); | 683 Node::Escape_state* state = this->sink_->state(this, NULL); |
557 state->loop_depth = -1; | 684 state->loop_depth = -1; |
558 } | 685 } |
559 | 686 |
560 std::string | 687 std::string |
561 debug_function_name(Named_object* fn) | 688 debug_function_name(Named_object* fn) |
562 { | 689 { |
563 if (fn == NULL) | 690 if (fn == NULL) |
564 return "<S>"; | 691 return "<S>"; |
565 | 692 |
566 if (!fn->is_function() | 693 if (!fn->is_function()) |
567 || fn->func_value()->enclosing() == NULL) | |
568 return Gogo::unpack_hidden_name(fn->name()); | 694 return Gogo::unpack_hidden_name(fn->name()); |
569 | 695 |
570 // Closures are named ".$nested#" where # starts from 0 to distinguish | 696 std::string fnname = Gogo::unpack_hidden_name(fn->name()); |
571 // between closures. The cmd/gc closures are named in the format | 697 if (fn->func_value()->is_method()) |
572 // "enclosing.func#" where # starts from 1. If this is a closure, format | 698 { |
573 // its name to match cmd/gc. | 699 // Methods in gc compiler are named "T.m" or "(*T).m" where |
574 Named_object* enclosing = fn->func_value()->enclosing(); | 700 // T is the receiver type. Add the receiver here. |
575 | 701 Type* rt = fn->func_value()->type()->receiver()->type(); |
576 // Extract #. | 702 switch (rt->classification()) |
577 std::string name = Gogo::unpack_hidden_name(fn->name()); | 703 { |
578 int closure_num = Gogo::nested_function_num(fn->name()); | 704 case Type::TYPE_NAMED: |
579 closure_num++; | 705 fnname = rt->named_type()->name() + "." + fnname; |
580 | 706 break; |
581 name = Gogo::unpack_hidden_name(enclosing->name()); | 707 |
582 char buf[200]; | 708 case Type::TYPE_POINTER: |
583 snprintf(buf, sizeof buf, "%s.func%d", name.c_str(), closure_num); | 709 { |
584 return buf; | 710 Named_type* nt = rt->points_to()->named_type(); |
711 if (nt != NULL) | |
712 fnname = "(*" + nt->name() + ")." + fnname; | |
713 break; | |
714 } | |
715 | |
716 default: | |
717 break; | |
718 } | |
719 } | |
720 | |
721 return fnname; | |
585 } | 722 } |
586 | 723 |
587 // Return the name of the current function. | 724 // Return the name of the current function. |
588 | 725 |
589 std::string | 726 std::string |
600 { | 737 { |
601 if (fntype == NULL || fntype->results() == NULL) | 738 if (fntype == NULL || fntype->results() == NULL) |
602 return; | 739 return; |
603 | 740 |
604 Node::Escape_state* state = n->state(this, NULL); | 741 Node::Escape_state* state = n->state(this, NULL); |
742 state->retvals.clear(); | |
605 Location loc = n->location(); | 743 Location loc = n->location(); |
606 | 744 |
607 int i = 0; | 745 int i = 0; |
608 char buf[50]; | 746 char buf[50]; |
609 for (Typed_identifier_list::const_iterator p = fntype->results()->begin(); | 747 for (Typed_identifier_list::const_iterator p = fntype->results()->begin(); |
616 dummy_var->set_is_used(); | 754 dummy_var->set_is_used(); |
617 Named_object* dummy_no = | 755 Named_object* dummy_no = |
618 Named_object::make_variable(buf, NULL, dummy_var); | 756 Named_object::make_variable(buf, NULL, dummy_var); |
619 Node* dummy_node = Node::make_node(dummy_no); | 757 Node* dummy_node = Node::make_node(dummy_no); |
620 // Initialize the state of the dummy output node. | 758 // Initialize the state of the dummy output node. |
621 dummy_node->state(this, NULL); | 759 Node::Escape_state* dummy_node_state = dummy_node->state(this, NULL); |
760 dummy_node_state->loop_depth = this->loop_depth_; | |
622 | 761 |
623 // Add dummy node to the retvals of n. | 762 // Add dummy node to the retvals of n. |
624 state->retvals.push_back(dummy_node); | 763 state->retvals.push_back(dummy_node); |
625 } | 764 } |
626 } | 765 } |
627 | 766 |
628 | 767 |
629 // Apply an indirection to N and return the result. | 768 // Apply an indirection to N and return the result. |
630 // This really only works if N is an expression node; it essentially becomes | |
631 // Node::make_node(n->expr()->deref()). We need the escape context to set the | |
632 // correct loop depth, however. | |
633 | 769 |
634 Node* | 770 Node* |
635 Escape_context::add_dereference(Node* n) | 771 Escape_context::add_dereference(Node* n) |
636 { | 772 { |
637 // Just return the original node if we can't add an indirection. | 773 Expression* e = n->expr(); |
638 if (n->object() != NULL || n->statement() != NULL) | 774 Location loc = n->location(); |
639 return n; | 775 Node* ind; |
640 | 776 if (e != NULL |
641 Node* ind = Node::make_node(n->expr()->deref()); | 777 && e->type()->points_to() != NULL |
642 // Initialize the state if this node doesn't already exist. | 778 && !e->type()->points_to()->is_void_type()) |
643 ind->state(this, NULL); | 779 { |
780 // We don't dereference void*, which can be actually any pointer type. | |
781 Expression* deref_expr = Expression::make_unary(OPERATOR_MULT, e, loc); | |
782 ind = Node::make_node(deref_expr); | |
783 } | |
784 else | |
785 // The gc compiler simply makes an OIND node. We can't do it | |
786 // for non-pointer type because that will result in a type error. | |
787 // Instead, we model this by making a node with a special flavor. | |
788 ind = Node::make_indirect_node(n); | |
789 | |
790 // Initialize the state. | |
791 Node::Escape_state* state = ind->state(this, NULL); | |
792 state->loop_depth = n->state(this, NULL)->loop_depth; | |
644 return ind; | 793 return ind; |
645 } | 794 } |
646 | 795 |
647 void | 796 void |
648 Escape_context::track(Node* n) | 797 Escape_context::track(Node* n) |
680 } | 829 } |
681 | 830 |
682 | 831 |
683 // The -fgo-optimize-alloc flag activates this escape analysis. | 832 // The -fgo-optimize-alloc flag activates this escape analysis. |
684 | 833 |
685 Go_optimize optimize_allocation_flag("allocs"); | 834 Go_optimize optimize_allocation_flag("allocs", true); |
835 | |
836 // A helper function to compute whether a function name has a | |
837 // matching hash value. | |
838 | |
839 static bool | |
840 escape_hash_match(std::string suffix, std::string name) | |
841 { | |
842 if (suffix.empty()) | |
843 return true; | |
844 if (suffix.at(0) == '-') | |
845 return !escape_hash_match(suffix.substr(1), name); | |
846 | |
847 const char* p = name.c_str(); | |
848 Go_sha1_helper* sha1_helper = go_create_sha1_helper(); | |
849 sha1_helper->process_bytes(p, strlen(p)); | |
850 std::string s = sha1_helper->finish(); | |
851 delete sha1_helper; | |
852 | |
853 int j = suffix.size() - 1; | |
854 for (int i = s.size() - 1; i >= 0; i--) | |
855 { | |
856 char c = s.at(i); | |
857 for (int k = 0; k < 8; k++, j--, c>>=1) | |
858 { | |
859 if (j < 0) | |
860 return true; | |
861 char bit = suffix.at(j) - '0'; | |
862 if ((c&1) != bit) | |
863 return false; | |
864 } | |
865 } | |
866 return false; | |
867 } | |
686 | 868 |
687 // Analyze the program flow for escape information. | 869 // Analyze the program flow for escape information. |
688 | 870 |
689 void | 871 void |
690 Gogo::analyze_escape() | 872 Gogo::analyze_escape() |
691 { | 873 { |
692 if (!optimize_allocation_flag.is_enabled() || saw_errors()) | 874 if (saw_errors()) |
875 return; | |
876 | |
877 if (!optimize_allocation_flag.is_enabled() | |
878 && !this->compiling_runtime()) | |
879 // We always run escape analysis when compiling runtime. | |
693 return; | 880 return; |
694 | 881 |
695 // Discover strongly connected groups of functions to analyze for escape | 882 // Discover strongly connected groups of functions to analyze for escape |
696 // information in this package. | 883 // information in this package. |
697 this->discover_analysis_sets(); | 884 this->discover_analysis_sets(); |
698 | 885 |
886 if (!this->debug_escape_hash().empty()) | |
887 std::cerr << "debug-escape-hash " << this->debug_escape_hash() << "\n"; | |
888 | |
699 for (std::vector<Analysis_set>::iterator p = this->analysis_sets_.begin(); | 889 for (std::vector<Analysis_set>::iterator p = this->analysis_sets_.begin(); |
700 p != this->analysis_sets_.end(); | 890 p != this->analysis_sets_.end(); |
701 ++p) | 891 ++p) |
702 { | 892 { |
703 std::vector<Named_object*> stack = p->first; | 893 std::vector<Named_object*> stack = p->first; |
894 | |
895 if (!this->debug_escape_hash().empty()) | |
896 { | |
897 bool match = false; | |
898 for (std::vector<Named_object*>::const_iterator fn = stack.begin(); | |
899 fn != stack.end(); | |
900 ++fn) | |
901 match = match || escape_hash_match(this->debug_escape_hash(), (*fn)->message_name()); | |
902 if (!match) | |
903 { | |
904 // Escape analysis won't run on these functions, but still | |
905 // need to tag them, so the caller knows. | |
906 for (std::vector<Named_object*>::iterator fn = stack.begin(); | |
907 fn != stack.end(); | |
908 ++fn) | |
909 if ((*fn)->is_function()) | |
910 { | |
911 Function_type* fntype = (*fn)->func_value()->type(); | |
912 fntype->set_is_tagged(); | |
913 | |
914 std::cerr << "debug-escape-hash disables " << debug_function_name(*fn) << "\n"; | |
915 } | |
916 | |
917 continue; | |
918 } | |
919 for (std::vector<Named_object*>::const_iterator fn = stack.begin(); | |
920 fn != stack.end(); | |
921 ++fn) | |
922 if ((*fn)->is_function()) | |
923 std::cerr << "debug-escape-hash triggers " << debug_function_name(*fn) << "\n"; | |
924 } | |
925 | |
704 Escape_context* context = new Escape_context(this, p->second); | 926 Escape_context* context = new Escape_context(this, p->second); |
705 | 927 |
706 // Analyze the flow of each function; build the connection graph. | 928 // Analyze the flow of each function; build the connection graph. |
707 // This is the assign phase. | 929 // This is the assign phase. |
708 for (std::vector<Named_object*>::reverse_iterator fn = stack.rbegin(); | 930 for (std::vector<Named_object*>::reverse_iterator fn = stack.rbegin(); |
713 this->assign_connectivity(context, *fn); | 935 this->assign_connectivity(context, *fn); |
714 } | 936 } |
715 | 937 |
716 // Propagate levels across each dst. This is the flood phase. | 938 // Propagate levels across each dst. This is the flood phase. |
717 std::set<Node*> dsts = context->dsts(); | 939 std::set<Node*> dsts = context->dsts(); |
940 Unordered_map(Node*, int) escapes; | |
718 for (std::set<Node*>::iterator n = dsts.begin(); | 941 for (std::set<Node*>::iterator n = dsts.begin(); |
719 n != dsts.end(); | 942 n != dsts.end(); |
720 ++n) | 943 ++n) |
721 this->propagate_escape(context, *n); | 944 { |
945 escapes[*n] = (*n)->encoding(); | |
946 this->propagate_escape(context, *n); | |
947 } | |
948 for (;;) | |
949 { | |
950 // Reflood if the roots' escape states increase. Run until fix point. | |
951 // This is rare. | |
952 bool done = true; | |
953 for (std::set<Node*>::iterator n = dsts.begin(); | |
954 n != dsts.end(); | |
955 ++n) | |
956 { | |
957 if ((*n)->object() == NULL | |
958 && ((*n)->expr() == NULL | |
959 || ((*n)->expr()->var_expression() == NULL | |
960 && (*n)->expr()->enclosed_var_expression() == NULL | |
961 && (*n)->expr()->func_expression() == NULL))) | |
962 continue; | |
963 if (escapes[*n] != (*n)->encoding()) | |
964 { | |
965 done = false; | |
966 if (this->debug_escape_level() > 2) | |
967 go_inform((*n)->location(), "Reflooding %s %s", | |
968 debug_function_name((*n)->state(context, NULL)->fn).c_str(), | |
969 (*n)->ast_format(this).c_str()); | |
970 escapes[*n] = (*n)->encoding(); | |
971 this->propagate_escape(context, *n); | |
972 } | |
973 } | |
974 if (done) | |
975 break; | |
976 } | |
722 | 977 |
723 // Tag each exported function's parameters with escape information. | 978 // Tag each exported function's parameters with escape information. |
724 for (std::vector<Named_object*>::iterator fn = stack.begin(); | 979 for (std::vector<Named_object*>::iterator fn = stack.begin(); |
725 fn != stack.end(); | 980 fn != stack.end(); |
726 ++fn) | 981 ++fn) |
732 for (std::vector<Node*>::const_iterator n = noesc.begin(); | 987 for (std::vector<Node*>::const_iterator n = noesc.begin(); |
733 n != noesc.end(); | 988 n != noesc.end(); |
734 ++n) | 989 ++n) |
735 { | 990 { |
736 Node::Escape_state* state = (*n)->state(context, NULL); | 991 Node::Escape_state* state = (*n)->state(context, NULL); |
737 if (((*n)->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE)) | 992 if ((*n)->encoding() == Node::ESCAPE_NONE) |
738 go_inform((*n)->location(), "%s %s does not escape", | 993 go_inform((*n)->location(), "%s %s does not escape", |
739 strip_packed_prefix(this, debug_function_name(state->fn)).c_str(), | 994 strip_packed_prefix(this, debug_function_name(state->fn)).c_str(), |
740 (*n)->ast_format(this).c_str()); | 995 (*n)->ast_format(this).c_str()); |
741 } | 996 } |
742 // TODO(cmang): Which objects in context->noesc actually don't escape. | |
743 } | 997 } |
744 delete context; | 998 delete context; |
745 } | 999 } |
746 } | 1000 } |
747 | 1001 |
751 | 1005 |
752 class Escape_analysis_discover : public Traverse | 1006 class Escape_analysis_discover : public Traverse |
753 { | 1007 { |
754 public: | 1008 public: |
755 Escape_analysis_discover(Gogo* gogo) | 1009 Escape_analysis_discover(Gogo* gogo) |
756 : Traverse(traverse_functions), | 1010 : Traverse(traverse_functions | traverse_func_declarations), |
757 gogo_(gogo), component_ids_() | 1011 gogo_(gogo), component_ids_() |
758 { } | 1012 { } |
759 | 1013 |
760 int | 1014 int |
761 function(Named_object*); | 1015 function(Named_object*); |
1016 | |
1017 int | |
1018 function_declaration(Named_object*); | |
762 | 1019 |
763 int | 1020 int |
764 visit(Named_object*); | 1021 visit(Named_object*); |
765 | 1022 |
766 int | 1023 int |
785 | 1042 |
786 // Visit each function. | 1043 // Visit each function. |
787 | 1044 |
788 int | 1045 int |
789 Escape_analysis_discover::function(Named_object* fn) | 1046 Escape_analysis_discover::function(Named_object* fn) |
1047 { | |
1048 this->visit(fn); | |
1049 return TRAVERSE_CONTINUE; | |
1050 } | |
1051 | |
1052 int | |
1053 Escape_analysis_discover::function_declaration(Named_object* fn) | |
790 { | 1054 { |
791 this->visit(fn); | 1055 this->visit(fn); |
792 return TRAVERSE_CONTINUE; | 1056 return TRAVERSE_CONTINUE; |
793 } | 1057 } |
794 | 1058 |
831 int min = this->id; | 1095 int min = this->id; |
832 | 1096 |
833 this->stack_.push(fn); | 1097 this->stack_.push(fn); |
834 min = this->visit_code(fn, min); | 1098 min = this->visit_code(fn, min); |
835 if ((min == id || min == id + 1) | 1099 if ((min == id || min == id + 1) |
836 && fn->is_function() | 1100 && ((fn->is_function() && fn->func_value()->enclosing() == NULL) |
837 && fn->func_value()->enclosing() == NULL) | 1101 || fn->is_function_declaration())) |
838 { | 1102 { |
839 bool recursive = min == id; | 1103 bool recursive = min == id; |
840 std::vector<Named_object*> group; | 1104 std::vector<Named_object*> group; |
841 | 1105 |
842 for (; !this->stack_.empty(); this->stack_.pop()) | 1106 for (; !this->stack_.empty(); this->stack_.pop()) |
1010 Escape_context* context_; | 1274 Escape_context* context_; |
1011 // The current function being analyzed. | 1275 // The current function being analyzed. |
1012 Named_object* fn_; | 1276 Named_object* fn_; |
1013 }; | 1277 }; |
1014 | 1278 |
1279 // Helper function to detect self assignment like the following. | |
1280 // | |
1281 // func (b *Buffer) Foo() { | |
1282 // n, m := ... | |
1283 // b.buf = b.buf[n:m] | |
1284 // } | |
1285 | |
1286 static bool | |
1287 is_self_assignment(Expression* lhs, Expression* rhs) | |
1288 { | |
1289 Unary_expression* lue = | |
1290 (lhs->field_reference_expression() != NULL | |
1291 ? lhs->field_reference_expression()->expr()->unary_expression() | |
1292 : lhs->unary_expression()); | |
1293 Var_expression* lve = | |
1294 (lue != NULL && lue->op() == OPERATOR_MULT ? lue->operand()->var_expression() : NULL); | |
1295 Array_index_expression* raie = rhs->array_index_expression(); | |
1296 String_index_expression* rsie = rhs->string_index_expression(); | |
1297 Expression* rarray = | |
1298 (raie != NULL && raie->end() != NULL && raie->array()->type()->is_slice_type() | |
1299 ? raie->array() | |
1300 : (rsie != NULL && rsie->type()->is_string_type() ? rsie->string() : NULL)); | |
1301 Unary_expression* rue = | |
1302 (rarray != NULL && rarray->field_reference_expression() != NULL | |
1303 ? rarray->field_reference_expression()->expr()->unary_expression() | |
1304 : (rarray != NULL ? rarray->unary_expression() : NULL)); | |
1305 Var_expression* rve = | |
1306 (rue != NULL && rue->op() == OPERATOR_MULT ? rue->operand()->var_expression() : NULL); | |
1307 return lve != NULL && rve != NULL | |
1308 && lve->named_object() == rve->named_object(); | |
1309 } | |
1310 | |
1015 // Model statements within a function as assignments and flows between nodes. | 1311 // Model statements within a function as assignments and flows between nodes. |
1016 | 1312 |
1017 int | 1313 int |
1018 Escape_analysis_assign::statement(Block*, size_t*, Statement* s) | 1314 Escape_analysis_assign::statement(Block*, size_t*, Statement* s) |
1019 { | 1315 { |
1055 if (var->is_variable() | 1351 if (var->is_variable() |
1056 && var->var_value()->init() != NULL) | 1352 && var->var_value()->init() != NULL) |
1057 { | 1353 { |
1058 Node* init_node = Node::make_node(var->var_value()->init()); | 1354 Node* init_node = Node::make_node(var->var_value()->init()); |
1059 this->assign(var_node, init_node); | 1355 this->assign(var_node, init_node); |
1356 } | |
1357 } | |
1358 break; | |
1359 | |
1360 case Statement::STATEMENT_TEMPORARY: | |
1361 { | |
1362 Expression* init = s->temporary_statement()->init(); | |
1363 if (init != NULL) | |
1364 { | |
1365 Node* n = Node::make_node(init); | |
1366 if (s->temporary_statement()->value_escapes()) | |
1367 this->assign(this->context_->sink(), n); | |
1368 else | |
1369 this->assign(Node::make_node(s), n); | |
1060 } | 1370 } |
1061 } | 1371 } |
1062 break; | 1372 break; |
1063 | 1373 |
1064 case Statement::STATEMENT_LABEL: | 1374 case Statement::STATEMENT_LABEL: |
1082 case Statement::STATEMENT_SWITCH: | 1392 case Statement::STATEMENT_SWITCH: |
1083 case Statement::STATEMENT_TYPE_SWITCH: | 1393 case Statement::STATEMENT_TYPE_SWITCH: |
1084 // Want to model the assignment of each case variable to the switched upon | 1394 // Want to model the assignment of each case variable to the switched upon |
1085 // variable. This should be lowered into assignment statements; nothing | 1395 // variable. This should be lowered into assignment statements; nothing |
1086 // to here if that's the case. | 1396 // to here if that's the case. |
1087 // TODO(cmang): Verify. | |
1088 break; | 1397 break; |
1089 | 1398 |
1090 case Statement::STATEMENT_ASSIGNMENT: | 1399 case Statement::STATEMENT_ASSIGNMENT: |
1091 { | 1400 { |
1092 Assignment_statement* assn = s->assignment_statement(); | 1401 Assignment_statement* assn = s->assignment_statement(); |
1093 Node* lhs = Node::make_node(assn->lhs()); | 1402 Expression* lhs = assn->lhs(); |
1094 Node* rhs = Node::make_node(assn->rhs()); | 1403 Expression* rhs = assn->rhs(); |
1095 | 1404 Node* lhs_node = Node::make_node(lhs); |
1096 // TODO(cmang): Add special case for escape analysis no-op: | 1405 Node* rhs_node = Node::make_node(rhs); |
1097 // func (b *Buffer) Foo() { | 1406 |
1098 // n, m := ... | 1407 // Filter out the following special case. |
1099 // b.buf = b.buf[n:m] | 1408 // |
1100 // } | 1409 // func (b *Buffer) Foo() { |
1101 // This is okay for now, it just means b escapes; it is conservative. | 1410 // n, m := ... |
1102 this->assign(lhs, rhs); | 1411 // b.buf = b.buf[n:m] |
1412 // } | |
1413 // | |
1414 // This assignment is a no-op for escape analysis, | |
1415 // it does not store any new pointers into b that were not already there. | |
1416 // However, without this special case b will escape. | |
1417 if (is_self_assignment(lhs, rhs)) | |
1418 { | |
1419 if (debug_level != 0) | |
1420 go_inform(s->location(), "%s ignoring self-assignment to %s", | |
1421 strip_packed_prefix(gogo, this->context_->current_function_name()).c_str(), | |
1422 lhs_node->ast_format(gogo).c_str()); | |
1423 break; | |
1424 } | |
1425 | |
1426 this->assign(lhs_node, rhs_node); | |
1103 } | 1427 } |
1104 break; | 1428 break; |
1105 | 1429 |
1106 case Statement::STATEMENT_SEND: | 1430 case Statement::STATEMENT_SEND: |
1107 { | 1431 { |
1110 } | 1434 } |
1111 break; | 1435 break; |
1112 | 1436 |
1113 case Statement::STATEMENT_DEFER: | 1437 case Statement::STATEMENT_DEFER: |
1114 if (this->context_->loop_depth() == 1) | 1438 if (this->context_->loop_depth() == 1) |
1115 break; | 1439 { |
1440 // Defer statement may need to allocate a thunk. When it is | |
1441 // not inside a loop, this can be stack allocated, as it | |
1442 // runs before the function finishes. | |
1443 Node* n = Node::make_node(s); | |
1444 n->set_encoding(Node::ESCAPE_NONE); | |
1445 break; | |
1446 } | |
1116 // fallthrough | 1447 // fallthrough |
1117 | 1448 |
1118 case Statement::STATEMENT_GO: | 1449 case Statement::STATEMENT_GO: |
1119 { | 1450 { |
1120 // Defer f(x) or go f(x). | 1451 // Defer f(x) or go f(x). |
1137 } | 1468 } |
1138 } | 1469 } |
1139 } | 1470 } |
1140 break; | 1471 break; |
1141 | 1472 |
1142 // TODO(cmang): Associate returned values with dummy return nodes. | |
1143 | |
1144 default: | 1473 default: |
1145 break; | 1474 break; |
1146 } | 1475 } |
1147 return TRAVERSE_SKIP_COMPONENTS; | 1476 return TRAVERSE_SKIP_COMPONENTS; |
1477 } | |
1478 | |
1479 // Helper function to emit moved-to-heap diagnostics. | |
1480 | |
1481 static void | |
1482 move_to_heap(Gogo* gogo, Expression *expr) | |
1483 { | |
1484 Named_object* no; | |
1485 if (expr->var_expression() != NULL) | |
1486 no = expr->var_expression()->named_object(); | |
1487 else if (expr->enclosed_var_expression() != NULL) | |
1488 no = expr->enclosed_var_expression()->variable(); | |
1489 else | |
1490 return; | |
1491 | |
1492 if ((no->is_variable() | |
1493 && !no->var_value()->is_global()) | |
1494 || no->is_result_variable()) | |
1495 { | |
1496 Node* n = Node::make_node(expr); | |
1497 if (gogo->debug_escape_level() != 0) | |
1498 go_inform(n->definition_location(), | |
1499 "moved to heap: %s", | |
1500 n->ast_format(gogo).c_str()); | |
1501 if (gogo->compiling_runtime() && gogo->package_name() == "runtime") | |
1502 go_error_at(expr->location(), | |
1503 "%s escapes to heap, not allowed in runtime", | |
1504 n->ast_format(gogo).c_str()); | |
1505 } | |
1148 } | 1506 } |
1149 | 1507 |
1150 // Model expressions within a function as assignments and flows between nodes. | 1508 // Model expressions within a function as assignments and flows between nodes. |
1151 | 1509 |
1152 int | 1510 int |
1159 Node* n = Node::make_node(*pexpr); | 1517 Node* n = Node::make_node(*pexpr); |
1160 if ((n->encoding() & ESCAPE_MASK) != int(Node::ESCAPE_HEAP) | 1518 if ((n->encoding() & ESCAPE_MASK) != int(Node::ESCAPE_HEAP) |
1161 && n->is_big(this->context_)) | 1519 && n->is_big(this->context_)) |
1162 { | 1520 { |
1163 if (debug_level > 1) | 1521 if (debug_level > 1) |
1164 go_inform((*pexpr)->location(), "too large for stack"); | 1522 go_inform((*pexpr)->location(), "%s too large for stack", |
1523 n->ast_format(gogo).c_str()); | |
1524 move_to_heap(gogo, *pexpr); | |
1165 n->set_encoding(Node::ESCAPE_HEAP); | 1525 n->set_encoding(Node::ESCAPE_HEAP); |
1166 (*pexpr)->address_taken(true); | 1526 (*pexpr)->address_taken(true); |
1167 this->assign(this->context_->sink(), n); | 1527 this->assign(this->context_->sink(), n); |
1168 } | 1528 } |
1169 | 1529 |
1182 switch ((*pexpr)->classification()) | 1542 switch ((*pexpr)->classification()) |
1183 { | 1543 { |
1184 case Expression::EXPRESSION_CALL: | 1544 case Expression::EXPRESSION_CALL: |
1185 { | 1545 { |
1186 Call_expression* call = (*pexpr)->call_expression(); | 1546 Call_expression* call = (*pexpr)->call_expression(); |
1187 this->call(call); | 1547 if (call->is_builtin()) |
1188 | 1548 { |
1549 Builtin_call_expression* bce = call->builtin_call_expression(); | |
1550 switch (bce->code()) | |
1551 { | |
1552 case Builtin_call_expression::BUILTIN_PANIC: | |
1553 { | |
1554 // Argument could leak through recover. | |
1555 Node* panic_arg = Node::make_node(call->args()->front()); | |
1556 this->assign(this->context_->sink(), panic_arg); | |
1557 } | |
1558 break; | |
1559 | |
1560 case Builtin_call_expression::BUILTIN_APPEND: | |
1561 { | |
1562 // The contents being appended leak. | |
1563 if (call->is_varargs()) | |
1564 { | |
1565 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do | |
1566 Node* appended = Node::make_node(call->args()->back()); | |
1567 this->assign_deref(this->context_->sink(), appended); | |
1568 if (debug_level > 2) | |
1569 go_inform((*pexpr)->location(), | |
1570 "special treatment of append(slice1, slice2...)"); | |
1571 } | |
1572 else | |
1573 { | |
1574 for (Expression_list::const_iterator pa = | |
1575 call->args()->begin() + 1; | |
1576 pa != call->args()->end(); | |
1577 ++pa) | |
1578 { | |
1579 Node* arg = Node::make_node(*pa); | |
1580 this->assign(this->context_->sink(), arg); | |
1581 } | |
1582 } | |
1583 | |
1584 // The content of the original slice leaks as well. | |
1585 Node* appendee = Node::make_node(call->args()->front()); | |
1586 this->assign_deref(this->context_->sink(), appendee); | |
1587 } | |
1588 break; | |
1589 | |
1590 case Builtin_call_expression::BUILTIN_COPY: | |
1591 { | |
1592 // Lose track of the copied content. | |
1593 Node* copied = Node::make_node(call->args()->back()); | |
1594 this->assign_deref(this->context_->sink(), copied); | |
1595 } | |
1596 break; | |
1597 | |
1598 default: | |
1599 break; | |
1600 } | |
1601 break; | |
1602 } | |
1189 Func_expression* fe = call->fn()->func_expression(); | 1603 Func_expression* fe = call->fn()->func_expression(); |
1190 if (fe != NULL && fe->is_runtime_function()) | 1604 if (fe != NULL && fe->is_runtime_function()) |
1191 { | 1605 { |
1192 switch (fe->runtime_code()) | 1606 switch (fe->runtime_code()) |
1193 { | 1607 { |
1194 case Runtime::GOPANIC: | |
1195 { | |
1196 // Argument could leak through recover. | |
1197 Node* panic_arg = Node::make_node(call->args()->front()); | |
1198 this->assign(this->context_->sink(), panic_arg); | |
1199 } | |
1200 break; | |
1201 | |
1202 case Runtime::GROWSLICE: | |
1203 { | |
1204 // The contents being appended leak. | |
1205 if (call->is_varargs()) | |
1206 { | |
1207 Node* appended = Node::make_node(call->args()->back()); | |
1208 this->assign_deref(this->context_->sink(), appended); | |
1209 } | |
1210 else | |
1211 { | |
1212 for (Expression_list::const_iterator pa = | |
1213 call->args()->begin(); | |
1214 pa != call->args()->end(); | |
1215 ++pa) | |
1216 { | |
1217 Node* arg = Node::make_node(*pa); | |
1218 this->assign(this->context_->sink(), arg); | |
1219 } | |
1220 } | |
1221 | |
1222 if (debug_level > 2) | |
1223 go_error_at((*pexpr)->location(), | |
1224 "special treatment of append(slice1, slice2...)"); | |
1225 | |
1226 // The content of the original slice leaks as well. | |
1227 Node* appendee = Node::make_node(call->args()->front()); | |
1228 this->assign_deref(this->context_->sink(), appendee); | |
1229 } | |
1230 break; | |
1231 | |
1232 case Runtime::SLICECOPY: | |
1233 case Runtime::SLICESTRINGCOPY: | |
1234 case Runtime::TYPEDSLICECOPY: | |
1235 { | |
1236 // Lose track of the copied content. | |
1237 Node* copied = Node::make_node(call->args()->back()); | |
1238 this->assign_deref(this->context_->sink(), copied); | |
1239 } | |
1240 break; | |
1241 | |
1242 case Runtime::MAKECHAN: | 1608 case Runtime::MAKECHAN: |
1609 case Runtime::MAKECHAN64: | |
1243 case Runtime::MAKEMAP: | 1610 case Runtime::MAKEMAP: |
1244 case Runtime::MAKESLICE: | 1611 case Runtime::MAKESLICE: |
1245 case Runtime::MAKESLICE64: | 1612 case Runtime::MAKESLICE64: |
1246 case Runtime::SLICEBYTETOSTRING: | 1613 this->context_->track(n); |
1247 case Runtime::SLICERUNETOSTRING: | |
1248 case Runtime::STRINGTOSLICEBYTE: | |
1249 case Runtime::STRINGTOSLICERUNE: | |
1250 case Runtime::CONCATSTRINGS: | |
1251 case Runtime::CONCATSTRING2: | |
1252 case Runtime::CONCATSTRING3: | |
1253 case Runtime::CONCATSTRING4: | |
1254 case Runtime::CONCATSTRING5: | |
1255 case Runtime::CONSTRUCT_MAP: | |
1256 case Runtime::INTSTRING: | |
1257 { | |
1258 Node* runtime_node = Node::make_node(fe); | |
1259 this->context_->track(runtime_node); | |
1260 } | |
1261 break; | 1614 break; |
1615 | |
1616 case Runtime::MAPASSIGN: | |
1617 { | |
1618 // Map key escapes. The last argument is the address | |
1619 // of the key. | |
1620 Node* key_node = Node::make_node(call->args()->back()); | |
1621 this->assign_deref(this->context_->sink(), key_node); | |
1622 } | |
1623 break; | |
1624 | |
1625 case Runtime::IFACEE2T2: | |
1626 case Runtime::IFACEI2T2: | |
1627 { | |
1628 // x, ok = v.(T), where T is non-pointer non-interface, | |
1629 // is lowered to | |
1630 // ok = IFACEI2T2(type, v, (void*)&tmp_x) | |
1631 // Here v flows to tmp_x. | |
1632 // Note: other IFACEX2Y2 returns the conversion result. | |
1633 // Those are handled in ::assign. | |
1634 Node* src_node = Node::make_node(call->args()->at(1)); | |
1635 Node* dst_node; | |
1636 Expression* arg2 = call->args()->at(2); | |
1637 // Try to pull tmp_x out of the arg2 expression, and let v | |
1638 // flows into it, instead of simply dereference arg2, | |
1639 // which looks like dereference of an arbitrary pointer | |
1640 // and causes v immediately escape. | |
1641 // The expression form matches statement.cc, | |
1642 // Tuple_type_guard_assignment_statement::lower_to_object_type. | |
1643 Unary_expression* ue = | |
1644 (arg2->conversion_expression() != NULL | |
1645 ? arg2->conversion_expression()->expr()->unary_expression() | |
1646 : arg2->unary_expression()); | |
1647 if (ue != NULL && ue->op() == OPERATOR_AND) | |
1648 { | |
1649 if (!ue->operand()->type()->has_pointer()) | |
1650 // Don't bother flowing non-pointer. | |
1651 break; | |
1652 dst_node = Node::make_node(ue->operand()); | |
1653 } | |
1654 else | |
1655 dst_node = this->context_->add_dereference(Node::make_node(arg2)); | |
1656 this->assign(dst_node, src_node); | |
1657 } | |
1658 break; | |
1262 | 1659 |
1263 default: | 1660 default: |
1264 break; | 1661 break; |
1265 } | 1662 } |
1266 } | 1663 } |
1664 else | |
1665 this->call(call); | |
1267 } | 1666 } |
1268 break; | 1667 break; |
1269 | 1668 |
1270 case Expression::EXPRESSION_ALLOCATION: | 1669 case Expression::EXPRESSION_ALLOCATION: |
1271 { | 1670 // This is Runtime::NEW. |
1272 // Same as above; this is Runtime::NEW. | 1671 this->context_->track(n); |
1273 Node* alloc_node = Node::make_node(*pexpr); | 1672 break; |
1274 this->context_->track(alloc_node); | 1673 |
1275 } | 1674 case Expression::EXPRESSION_STRING_CONCAT: |
1675 this->context_->track(n); | |
1276 break; | 1676 break; |
1277 | 1677 |
1278 case Expression::EXPRESSION_CONVERSION: | 1678 case Expression::EXPRESSION_CONVERSION: |
1279 { | 1679 { |
1280 Type_conversion_expression* tce = (*pexpr)->conversion_expression(); | 1680 Type_conversion_expression* tce = (*pexpr)->conversion_expression(); |
1681 Type* ft = tce->expr()->type(); | |
1682 Type* tt = tce->type(); | |
1683 if ((ft->is_string_type() && tt->is_slice_type()) | |
1684 || (ft->is_slice_type() && tt->is_string_type()) | |
1685 || (ft->integer_type() != NULL && tt->is_string_type())) | |
1686 { | |
1687 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune) | |
1688 this->context_->track(n); | |
1689 break; | |
1690 } | |
1281 Node* tce_node = Node::make_node(tce); | 1691 Node* tce_node = Node::make_node(tce); |
1282 Node* converted = Node::make_node(tce->expr()); | 1692 Node* converted = Node::make_node(tce->expr()); |
1283 this->context_->track(tce_node); | 1693 this->context_->track(tce_node); |
1284 | 1694 |
1285 this->assign(tce_node, converted); | 1695 this->assign(tce_node, converted); |
1393 Expression_list::const_iterator p = sce->vals()->begin(); | 1803 Expression_list::const_iterator p = sce->vals()->begin(); |
1394 ++p; | 1804 ++p; |
1395 for (; p != sce->vals()->end(); ++p) | 1805 for (; p != sce->vals()->end(); ++p) |
1396 { | 1806 { |
1397 Node* enclosed_node = Node::make_node(*p); | 1807 Node* enclosed_node = Node::make_node(*p); |
1398 Node::Escape_state* state = | 1808 this->context_->track(enclosed_node); |
1399 enclosed_node->state(this->context_, NULL); | |
1400 state->loop_depth = this->context_->loop_depth(); | |
1401 this->assign(closure_node, enclosed_node); | 1809 this->assign(closure_node, enclosed_node); |
1402 } | 1810 } |
1403 } | 1811 } |
1404 } | 1812 } |
1405 break; | 1813 break; |
1406 | 1814 |
1407 case Expression::EXPRESSION_UNARY: | 1815 case Expression::EXPRESSION_UNARY: |
1408 { | 1816 { |
1409 if ((*pexpr)->unary_expression()->op() != OPERATOR_AND) | |
1410 break; | |
1411 | |
1412 Node* addr_node = Node::make_node(*pexpr); | |
1413 this->context_->track(addr_node); | |
1414 | |
1415 Expression* operand = (*pexpr)->unary_expression()->operand(); | 1817 Expression* operand = (*pexpr)->unary_expression()->operand(); |
1416 Named_object* var = NULL; | 1818 |
1417 if (operand->var_expression() != NULL) | 1819 if ((*pexpr)->unary_expression()->op() == OPERATOR_AND) |
1418 var = operand->var_expression()->named_object(); | 1820 { |
1419 else if (operand->enclosed_var_expression() != NULL) | 1821 this->context_->track(n); |
1420 var = operand->enclosed_var_expression()->variable(); | 1822 |
1421 else if (operand->temporary_reference_expression() != NULL) | 1823 Named_object* var = NULL; |
1422 { | 1824 if (operand->var_expression() != NULL) |
1423 // Found in runtime/chanbarrier_test.go. The address of a struct | 1825 var = operand->var_expression()->named_object(); |
1424 // reference is usually a heap expression, except when it is a part | 1826 else if (operand->enclosed_var_expression() != NULL) |
1425 // of a case statement. In that case, it is lowered into a | 1827 var = operand->enclosed_var_expression()->variable(); |
1426 // temporary reference and never linked to the heap expression that | 1828 |
1427 // initializes it. In general, when taking the address of some | 1829 if (var != NULL |
1428 // temporary, the analysis should really be looking at the initial | 1830 && ((var->is_variable() && var->var_value()->is_parameter()) |
1429 // value of that temporary. | 1831 || var->is_result_variable())) |
1430 Temporary_reference_expression* tre = | 1832 { |
1431 operand->temporary_reference_expression(); | 1833 Node::Escape_state* addr_state = n->state(this->context_, NULL); |
1432 if (tre->statement() != NULL | 1834 addr_state->loop_depth = 1; |
1433 && tre->statement()->temporary_statement()->init() != NULL) | 1835 break; |
1434 { | 1836 } |
1435 Expression* init = | 1837 } |
1436 tre->statement()->temporary_statement()->init(); | 1838 |
1437 Node* init_node = Node::make_node(init); | 1839 if ((*pexpr)->unary_expression()->op() != OPERATOR_AND |
1438 this->assign(addr_node, init_node); | 1840 && (*pexpr)->unary_expression()->op() != OPERATOR_MULT) |
1439 } | 1841 break; |
1440 } | 1842 |
1441 | 1843 // For &x and *x, use the loop depth of x if known. |
1442 if (var == NULL) | 1844 Node::Escape_state* expr_state = n->state(this->context_, NULL); |
1443 break; | 1845 Node* operand_node = Node::make_node(operand); |
1444 | 1846 Node::Escape_state* operand_state = operand_node->state(this->context_, NULL); |
1445 if (var->is_variable() | 1847 if (operand_state->loop_depth != 0) |
1446 && !var->var_value()->is_parameter()) | 1848 expr_state->loop_depth = operand_state->loop_depth; |
1447 { | 1849 } |
1448 // For &x, use the loop depth of x if known. | 1850 break; |
1449 Node::Escape_state* addr_state = | 1851 |
1450 addr_node->state(this->context_, NULL); | 1852 case Expression::EXPRESSION_ARRAY_INDEX: |
1451 Node* operand_node = Node::make_node(operand); | 1853 { |
1452 Node::Escape_state* operand_state = | 1854 Array_index_expression* aie = (*pexpr)->array_index_expression(); |
1453 operand_node->state(this->context_, NULL); | 1855 |
1454 if (operand_state->loop_depth != 0) | 1856 // Propagate the loopdepth to element. |
1455 addr_state->loop_depth = operand_state->loop_depth; | 1857 Node* array_node = Node::make_node(aie->array()); |
1456 } | 1858 Node::Escape_state* elem_state = n->state(this->context_, NULL); |
1457 else if ((var->is_variable() | 1859 Node::Escape_state* array_state = array_node->state(this->context_, NULL); |
1458 && var->var_value()->is_parameter()) | 1860 elem_state->loop_depth = array_state->loop_depth; |
1459 || var->is_result_variable()) | 1861 |
1460 { | 1862 if (aie->end() != NULL && !aie->array()->type()->is_slice_type()) |
1461 Node::Escape_state* addr_state = | 1863 { |
1462 addr_node->state(this->context_, NULL); | 1864 // Slicing an array. This effectively takes the address of the array. |
1463 addr_state->loop_depth = 1; | 1865 Expression* addr = Expression::make_unary(OPERATOR_AND, aie->array(), |
1464 } | 1866 aie->location()); |
1867 Node* addr_node = Node::make_node(addr); | |
1868 n->set_child(addr_node); | |
1869 this->context_->track(addr_node); | |
1870 | |
1871 Node::Escape_state* addr_state = addr_node->state(this->context_, NULL); | |
1872 addr_state->loop_depth = array_state->loop_depth; | |
1873 } | |
1874 } | |
1875 break; | |
1876 | |
1877 case Expression::EXPRESSION_FIELD_REFERENCE: | |
1878 { | |
1879 // Propagate the loopdepth to field. | |
1880 Node* struct_node = | |
1881 Node::make_node((*pexpr)->field_reference_expression()->expr()); | |
1882 Node::Escape_state* field_state = n->state(this->context_, NULL); | |
1883 Node::Escape_state* struct_state = struct_node->state(this->context_, NULL); | |
1884 field_state->loop_depth = struct_state->loop_depth; | |
1465 } | 1885 } |
1466 break; | 1886 break; |
1467 | 1887 |
1468 default: | 1888 default: |
1469 break; | 1889 break; |
1525 (*p)->ast_format(gogo).c_str()); | 1945 (*p)->ast_format(gogo).c_str()); |
1526 this->assign(this->context_->sink(), *p); | 1946 this->assign(this->context_->sink(), *p); |
1527 } | 1947 } |
1528 | 1948 |
1529 this->context_->init_retvals(call_node, fntype); | 1949 this->context_->init_retvals(call_node, fntype); |
1950 | |
1951 // It could be a closure call that returns captured variable. | |
1952 // Model this by flowing the func expression to result. | |
1953 // See issue #14409. | |
1954 Node* fn_node = Node::make_node(call->fn()); | |
1955 std::vector<Node*> retvals = call_node->state(this->context_, NULL)->retvals; | |
1956 for (std::vector<Node*>::const_iterator p = retvals.begin(); | |
1957 p != retvals.end(); | |
1958 ++p) | |
1959 this->assign_deref(*p, fn_node); | |
1960 | |
1530 return; | 1961 return; |
1531 } | 1962 } |
1532 | 1963 |
1533 // If FN is an untagged function. | 1964 // If FN is an untagged function. |
1534 if (fn != NULL | 1965 if (fn != NULL |
1539 go_inform(call->location(), "esccall:: %s in recursive group", | 1970 go_inform(call->location(), "esccall:: %s in recursive group", |
1540 call_node->ast_format(gogo).c_str()); | 1971 call_node->ast_format(gogo).c_str()); |
1541 | 1972 |
1542 Function* f = fn->named_object()->func_value(); | 1973 Function* f = fn->named_object()->func_value(); |
1543 const Bindings* callee_bindings = f->block()->bindings(); | 1974 const Bindings* callee_bindings = f->block()->bindings(); |
1544 | 1975 Function::Results* results = f->result_variables(); |
1545 const Typed_identifier_list* results = fntype->results(); | |
1546 if (results != NULL) | 1976 if (results != NULL) |
1547 { | 1977 { |
1548 // Setup output list on this call node. | 1978 // Setup output list on this call node. |
1549 Node::Escape_state* state = call_node->state(this->context_, NULL); | 1979 Node::Escape_state* state = call_node->state(this->context_, NULL); |
1550 for (Typed_identifier_list::const_iterator p1 = results->begin(); | 1980 for (Function::Results::const_iterator p1 = results->begin(); |
1551 p1 != results->end(); | 1981 p1 != results->end(); |
1552 ++p1) | 1982 ++p1) |
1553 { | 1983 { |
1554 if (p1->name().empty() || Gogo::is_sink_name(p1->name())) | 1984 Node* result_node = Node::make_node(*p1); |
1555 continue; | |
1556 | |
1557 Named_object* result_no = | |
1558 callee_bindings->lookup_local(p1->name()); | |
1559 go_assert(result_no != NULL); | |
1560 Node* result_node = Node::make_node(result_no); | |
1561 state->retvals.push_back(result_node); | 1985 state->retvals.push_back(result_node); |
1562 } | 1986 } |
1563 } | 1987 } |
1564 | 1988 |
1565 std::vector<Node*>::iterator p = arg_nodes.begin(); | 1989 std::vector<Node*>::iterator p = arg_nodes.begin(); |
1566 if (fntype->is_method() | 1990 if (fntype->is_method()) |
1567 && fntype->receiver()->type()->has_pointer()) | |
1568 { | 1991 { |
1569 std::string rcvr_name = fntype->receiver()->name(); | 1992 std::string rcvr_name = fntype->receiver()->name(); |
1570 if (rcvr_name.empty() || Gogo::is_sink_name(rcvr_name)) | 1993 if (rcvr_name.empty() || Gogo::is_sink_name(rcvr_name) |
1994 || !fntype->receiver()->type()->has_pointer()) | |
1571 ; | 1995 ; |
1572 else | 1996 else |
1573 { | 1997 { |
1574 Named_object* rcvr_no = | 1998 Named_object* rcvr_no = |
1575 callee_bindings->lookup_local(fntype->receiver()->name()); | 1999 callee_bindings->lookup_local(fntype->receiver()->name()); |
1576 go_assert(rcvr_no != NULL); | 2000 go_assert(rcvr_no != NULL); |
1577 Node* rcvr_node = Node::make_node(rcvr_no); | 2001 Node* rcvr_node = Node::make_node(rcvr_no); |
1578 this->assign(rcvr_node, *p); | 2002 if (fntype->receiver()->type()->points_to() == NULL |
2003 && (*p)->expr()->type()->points_to() != NULL) | |
2004 // This is a call to a value method that has been lowered into a call | |
2005 // to a pointer method. Gccgo generates a pointer method for all | |
2006 // method calls and takes the address of the value passed as the | |
2007 // receiver then immediately dereferences it within the function. | |
2008 // In this case, the receiver address does not escape; its content | |
2009 // flows to the call. | |
2010 this->assign_deref(rcvr_node, *p); | |
2011 else | |
2012 this->assign(rcvr_node, *p); | |
1579 } | 2013 } |
1580 ++p; | 2014 ++p; |
1581 } | 2015 } |
1582 | 2016 |
1583 const Typed_identifier_list* til = fntype->parameters(); | 2017 const Typed_identifier_list* til = fntype->parameters(); |
1626 this->context_->init_retvals(call_node, fntype); | 2060 this->context_->init_retvals(call_node, fntype); |
1627 | 2061 |
1628 // Receiver. | 2062 // Receiver. |
1629 std::vector<Node*>::iterator p = arg_nodes.begin(); | 2063 std::vector<Node*>::iterator p = arg_nodes.begin(); |
1630 if (fntype->is_method() | 2064 if (fntype->is_method() |
1631 && fntype->receiver()->type()->has_pointer() | |
1632 && p != arg_nodes.end()) | 2065 && p != arg_nodes.end()) |
1633 { | 2066 { |
1634 // First argument to call will be the receiver. | 2067 // First argument to call will be the receiver. |
1635 std::string* note = fntype->receiver()->note(); | 2068 std::string* note = fntype->receiver()->note(); |
1636 if (fntype->receiver()->type()->points_to() == NULL | 2069 if (fntype->receiver()->type()->points_to() == NULL |
1637 && (*p)->expr()->unary_expression() != NULL | 2070 && (*p)->expr()->type()->points_to() != NULL) |
1638 && (*p)->expr()->unary_expression()->op() == OPERATOR_AND) | 2071 // This is a call to a value method that has been lowered into a call |
1639 { | 2072 // to a pointer method. Gccgo generates a pointer method for all |
1640 // This is a call to a value method that has been lowered into a call | 2073 // method calls and takes the address of the value passed as the |
1641 // to a pointer method. Gccgo generates a pointer method for all | 2074 // receiver then immediately dereferences it within the function. |
1642 // method calls and takes the address of the value passed as the | 2075 // In this case, the receiver address does not escape; its content |
1643 // receiver then immediately dereferences it within the function. | 2076 // flows to the call. |
1644 // In this case, the receiver does not escape. | 2077 this->assign_from_note(note, call_state->retvals, |
1645 } | 2078 this->context_->add_dereference(*p)); |
1646 else | 2079 else |
1647 { | 2080 { |
1648 if (!Type::are_identical(fntype->receiver()->type(), | 2081 if (!Type::are_identical(fntype->receiver()->type(), |
1649 (*p)->expr()->type(), true, NULL)) | 2082 (*p)->expr()->type(), Type::COMPARE_TAGS, |
2083 NULL)) | |
1650 { | 2084 { |
1651 // This will be converted later, preemptively track it instead | 2085 // This will be converted later, preemptively track it instead |
1652 // of its conversion expression which will show up in a later pass. | 2086 // of its conversion expression which will show up in a later pass. |
1653 this->context_->track(*p); | 2087 this->context_->track(*p); |
1654 } | 2088 } |
1663 for (Typed_identifier_list::const_iterator pn = til->begin(); | 2097 for (Typed_identifier_list::const_iterator pn = til->begin(); |
1664 pn != til->end() && p != arg_nodes.end(); | 2098 pn != til->end() && p != arg_nodes.end(); |
1665 ++pn, ++p) | 2099 ++pn, ++p) |
1666 { | 2100 { |
1667 if (!Type::are_identical(pn->type(), (*p)->expr()->type(), | 2101 if (!Type::are_identical(pn->type(), (*p)->expr()->type(), |
1668 true, NULL)) | 2102 Type::COMPARE_TAGS, NULL)) |
1669 { | 2103 { |
1670 // This will be converted later, preemptively track it instead | 2104 // This will be converted later, preemptively track it instead |
1671 // of its conversion expression which will show up in a later pass. | 2105 // of its conversion expression which will show up in a later pass. |
1672 this->context_->track(*p); | 2106 this->context_->track(*p); |
1673 } | 2107 } |
1674 | 2108 |
1675 // TODO(cmang): Special care for varargs parameter? | |
1676 Type* t = pn->type(); | 2109 Type* t = pn->type(); |
1677 if (t != NULL | 2110 if (t != NULL |
1678 && t->has_pointer()) | 2111 && t->has_pointer()) |
1679 { | 2112 { |
1680 std::string* note = pn->note(); | 2113 std::string* note = pn->note(); |
1681 int enc = this->assign_from_note(note, call_state->retvals, *p); | 2114 int enc = this->assign_from_note(note, call_state->retvals, *p); |
1682 if (enc == Node::ESCAPE_NONE | 2115 if (enc == Node::ESCAPE_NONE |
1683 && (call->is_deferred() | 2116 && !call->is_deferred() |
1684 || call->is_concurrent())) | 2117 && !call->is_concurrent()) |
1685 { | 2118 { |
1686 // TODO(cmang): Mark the argument as strictly non-escaping. | 2119 // TODO(cmang): Mark the argument as strictly non-escaping? |
2120 // In the gc compiler this is for limiting the lifetime of | |
2121 // temporaries. We probably don't need this? | |
1687 } | 2122 } |
1688 } | 2123 } |
1689 } | 2124 } |
1690 | 2125 |
1691 for (; p != arg_nodes.end(); ++p) | 2126 for (; p != arg_nodes.end(); ++p) |
1716 dst->ast_format(gogo).c_str(), dst->details().c_str(), | 2151 dst->ast_format(gogo).c_str(), dst->details().c_str(), |
1717 dst->op_format().c_str(), | 2152 dst->op_format().c_str(), |
1718 src->ast_format(gogo).c_str(), src->details().c_str(), | 2153 src->ast_format(gogo).c_str(), src->details().c_str(), |
1719 src->op_format().c_str()); | 2154 src->op_format().c_str()); |
1720 | 2155 |
1721 if (dst->expr() != NULL) | 2156 if (dst->is_indirect()) |
2157 // Lose track of the dereference. | |
2158 dst = this->context_->sink(); | |
2159 else if (dst->expr() != NULL) | |
1722 { | 2160 { |
1723 // Analyze the lhs of the assignment. | 2161 // Analyze the lhs of the assignment. |
1724 // Replace DST with this->context_->sink() if we can't track it. | 2162 // Replace DST with this->context_->sink() if we can't track it. |
1725 Expression* e = dst->expr(); | 2163 Expression* e = dst->expr(); |
1726 switch (e->classification()) | 2164 switch (e->classification()) |
1783 | 2221 |
1784 dst = this->context_->sink(); | 2222 dst = this->context_->sink(); |
1785 } | 2223 } |
1786 break; | 2224 break; |
1787 | 2225 |
2226 case Expression::EXPRESSION_TEMPORARY_REFERENCE: | |
2227 { | |
2228 // Temporary is tracked through the underlying Temporary_statement. | |
2229 Temporary_statement* t = | |
2230 dst->expr()->temporary_reference_expression()->statement(); | |
2231 if (t->value_escapes()) | |
2232 dst = this->context_->sink(); | |
2233 else | |
2234 dst = Node::make_node(t); | |
2235 } | |
2236 break; | |
2237 | |
1788 default: | 2238 default: |
1789 // TODO(cmang): Add debugging info here: only a few expressions | 2239 // TODO(cmang): Add debugging info here: only a few expressions |
1790 // should leave DST unmodified. | 2240 // should leave DST unmodified. |
1791 break; | 2241 break; |
1792 } | 2242 } |
1793 } | 2243 } |
1794 | 2244 |
1795 if (src->expr() != NULL) | 2245 if (src->object() != NULL) |
2246 this->flows(dst, src); | |
2247 else if (src->is_indirect()) | |
2248 this->flows(dst, src); | |
2249 else if (src->expr() != NULL) | |
1796 { | 2250 { |
1797 Expression* e = src->expr(); | 2251 Expression* e = src->expr(); |
1798 switch (e->classification()) | 2252 switch (e->classification()) |
1799 { | 2253 { |
1800 case Expression::EXPRESSION_VAR_REFERENCE: | 2254 case Expression::EXPRESSION_VAR_REFERENCE: |
2255 case Expression::EXPRESSION_ENCLOSED_VAR_REFERENCE: | |
1801 // DST = var | 2256 // DST = var |
1802 case Expression::EXPRESSION_HEAP: | 2257 case Expression::EXPRESSION_HEAP: |
1803 // DST = &T{...}. | 2258 // DST = &T{...}. |
1804 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION: | 2259 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION: |
1805 case Expression::EXPRESSION_SLICE_CONSTRUCTION: | 2260 case Expression::EXPRESSION_SLICE_CONSTRUCTION: |
1810 // DST = T{...}. | 2265 // DST = T{...}. |
1811 case Expression::EXPRESSION_ALLOCATION: | 2266 case Expression::EXPRESSION_ALLOCATION: |
1812 // DST = new(T). | 2267 // DST = new(T). |
1813 case Expression::EXPRESSION_BOUND_METHOD: | 2268 case Expression::EXPRESSION_BOUND_METHOD: |
1814 // DST = x.M. | 2269 // DST = x.M. |
2270 case Expression::EXPRESSION_STRING_CONCAT: | |
2271 // DST = str1 + str2 | |
1815 this->flows(dst, src); | 2272 this->flows(dst, src); |
1816 break; | 2273 break; |
1817 | 2274 |
1818 case Expression::EXPRESSION_UNSAFE_CONVERSION: | 2275 case Expression::EXPRESSION_UNSAFE_CONVERSION: |
1819 { | 2276 { |
1821 Node* underlying_node = Node::make_node(underlying); | 2278 Node* underlying_node = Node::make_node(underlying); |
1822 this->assign(dst, underlying_node); | 2279 this->assign(dst, underlying_node); |
1823 } | 2280 } |
1824 break; | 2281 break; |
1825 | 2282 |
1826 case Expression::EXPRESSION_ENCLOSED_VAR_REFERENCE: | |
1827 { | |
1828 Named_object* var = e->enclosed_var_expression()->variable(); | |
1829 Node* var_node = Node::make_node(var); | |
1830 this->flows(dst, var_node); | |
1831 } | |
1832 break; | |
1833 | |
1834 case Expression::EXPRESSION_CALL: | 2283 case Expression::EXPRESSION_CALL: |
1835 { | 2284 { |
1836 Call_expression* call = e->call_expression(); | 2285 Call_expression* call = e->call_expression(); |
2286 if (call->is_builtin()) | |
2287 { | |
2288 Builtin_call_expression* bce = call->builtin_call_expression(); | |
2289 if (bce->code() == Builtin_call_expression::BUILTIN_APPEND) | |
2290 { | |
2291 // Append returns the first argument. | |
2292 // The subsequent arguments are already leaked because | |
2293 // they are operands to append. | |
2294 Node* appendee = Node::make_node(call->args()->front()); | |
2295 this->assign(dst, appendee); | |
2296 } | |
2297 break; | |
2298 } | |
1837 Func_expression* fe = call->fn()->func_expression(); | 2299 Func_expression* fe = call->fn()->func_expression(); |
1838 if (fe != NULL && fe->is_runtime_function()) | 2300 if (fe != NULL && fe->is_runtime_function()) |
1839 { | 2301 { |
1840 switch (fe->runtime_code()) | 2302 switch (fe->runtime_code()) |
1841 { | 2303 { |
1842 case Runtime::GROWSLICE: | |
1843 { | |
1844 // Append returns the first argument. | |
1845 // The subsequent arguments are already leaked because | |
1846 // they are operands to append. | |
1847 Node* appendee = Node::make_node(call->args()->front()); | |
1848 this->assign(dst, appendee); | |
1849 break; | |
1850 } | |
1851 | |
1852 case Runtime::MAKECHAN: | 2304 case Runtime::MAKECHAN: |
2305 case Runtime::MAKECHAN64: | |
1853 case Runtime::MAKEMAP: | 2306 case Runtime::MAKEMAP: |
1854 case Runtime::MAKESLICE: | 2307 case Runtime::MAKESLICE: |
1855 case Runtime::MAKESLICE64: | 2308 case Runtime::MAKESLICE64: |
1856 // DST = make(...). | 2309 // DST = make(...). |
1857 case Runtime::SLICEBYTETOSTRING: | 2310 this->flows(dst, src); |
1858 // DST = string([]byte{...}). | 2311 break; |
1859 case Runtime::SLICERUNETOSTRING: | |
1860 // DST = string([]int{...}). | |
1861 case Runtime::STRINGTOSLICEBYTE: | |
1862 // DST = []byte(str). | |
1863 case Runtime::STRINGTOSLICERUNE: | |
1864 // DST = []rune(str). | |
1865 case Runtime::CONCATSTRINGS: | |
1866 case Runtime::CONCATSTRING2: | |
1867 case Runtime::CONCATSTRING3: | |
1868 case Runtime::CONCATSTRING4: | |
1869 case Runtime::CONCATSTRING5: | |
1870 // DST = str1 + str2 | |
1871 case Runtime::CONSTRUCT_MAP: | |
1872 // When building a map literal's backend representation. | |
1873 // Likely never seen here and covered in | |
1874 // Expression::EXPRESSION_MAP_CONSTRUCTION. | |
1875 case Runtime::INTSTRING: | |
1876 // DST = string(i). | |
1877 case Runtime::IFACEE2E2: | |
1878 case Runtime::IFACEI2E2: | |
1879 case Runtime::IFACEE2I2: | |
1880 case Runtime::IFACEI2I2: | |
1881 case Runtime::IFACEE2T2P: | |
1882 case Runtime::IFACEI2T2P: | |
1883 case Runtime::IFACEE2T2: | |
1884 case Runtime::IFACEI2T2: | |
1885 case Runtime::REQUIREITAB: | |
1886 // All versions of interface conversion that might result | |
1887 // from a type assertion. Some of these are the result of | |
1888 // a tuple type assertion statement and may not be covered | |
1889 // by the case in Expression::EXPRESSION_CONVERSION or | |
1890 // Expression::EXPRESSION_TYPE_GUARD. | |
1891 this->flows(dst, src); | |
1892 break; | |
1893 | 2312 |
1894 default: | 2313 default: |
1895 break; | 2314 break; |
1896 } | 2315 } |
1897 break; | 2316 break; |
1907 Node* rcvr_node = Node::make_node(call->args()->front()); | 2326 Node* rcvr_node = Node::make_node(call->args()->front()); |
1908 this->assign(dst, rcvr_node); | 2327 this->assign(dst, rcvr_node); |
1909 break; | 2328 break; |
1910 } | 2329 } |
1911 | 2330 |
1912 // TODO(cmang): Handle case from issue 4529. | 2331 // Result flows to dst. |
1913 // Node* call_node = Node::make_node(e); | 2332 Node* call_node = Node::make_node(e); |
1914 // Node::Escape_state* call_state = call_node->state(this->context_, NULL); | 2333 Node::Escape_state* call_state = call_node->state(this->context_, NULL); |
1915 // std::vector<Node*> retvals = call_state->retvals; | 2334 std::vector<Node*> retvals = call_state->retvals; |
1916 // for (std::vector<Node*>::const_iterator p = retvals.begin(); | 2335 for (std::vector<Node*>::const_iterator p = retvals.begin(); |
1917 // p != retvals.end(); | 2336 p != retvals.end(); |
1918 // ++p) | 2337 ++p) |
1919 // this->flows(dst, *p); | 2338 this->flows(dst, *p); |
1920 } | 2339 } |
1921 break; | 2340 break; |
1922 | 2341 |
2342 case Expression::EXPRESSION_CALL_RESULT: | |
2343 { | |
2344 Call_result_expression* cre = e->call_result_expression(); | |
2345 Call_expression* call = cre->call()->call_expression(); | |
2346 if (call->is_builtin()) | |
2347 break; | |
2348 if (call->fn()->func_expression() != NULL | |
2349 && call->fn()->func_expression()->is_runtime_function()) | |
2350 { | |
2351 switch (call->fn()->func_expression()->runtime_code()) | |
2352 { | |
2353 case Runtime::IFACEE2E2: | |
2354 case Runtime::IFACEI2E2: | |
2355 case Runtime::IFACEE2I2: | |
2356 case Runtime::IFACEI2I2: | |
2357 case Runtime::IFACEE2T2P: | |
2358 case Runtime::IFACEI2T2P: | |
2359 { | |
2360 // x, ok = v.(T), where T is a pointer or interface, | |
2361 // is lowered to | |
2362 // x, ok = IFACEI2E2(v), or | |
2363 // x, ok = IFACEI2I2(type, v) | |
2364 // The last arg flows to the first result. | |
2365 // Note: IFACEX2T2 has different signature, handled by | |
2366 // ::expression. | |
2367 if (cre->index() != 0) | |
2368 break; | |
2369 Node* arg_node = Node::make_node(call->args()->back()); | |
2370 this->assign(dst, arg_node); | |
2371 } | |
2372 break; | |
2373 | |
2374 default: | |
2375 break; | |
2376 } | |
2377 break; | |
2378 } | |
2379 | |
2380 Node* call_node = Node::make_node(call); | |
2381 Node* ret_node = call_node->state(context_, NULL)->retvals[cre->index()]; | |
2382 this->assign(dst, ret_node); | |
2383 } | |
2384 break; | |
2385 | |
1923 case Expression::EXPRESSION_FUNC_REFERENCE: | 2386 case Expression::EXPRESSION_FUNC_REFERENCE: |
1924 if (e->func_expression()->closure() != NULL) | 2387 if (e->func_expression()->closure() != NULL) |
1925 { | 2388 this->flows(dst, src); |
1926 // If SRC is a reference to a function closure, DST flows into | |
1927 // the underyling closure variable. | |
1928 Expression* closure = e->func_expression()->closure(); | |
1929 Node* closure_node = Node::make_node(closure); | |
1930 this->flows(dst, closure_node); | |
1931 } | |
1932 break; | 2389 break; |
2390 | |
2391 case Expression::EXPRESSION_CONVERSION: | |
2392 { | |
2393 Type_conversion_expression* tce = e->conversion_expression(); | |
2394 Type* ft = tce->expr()->type(); | |
2395 Type* tt = tce->type(); | |
2396 if ((ft->is_string_type() && tt->is_slice_type()) | |
2397 || (ft->is_slice_type() && tt->is_string_type()) | |
2398 || (ft->integer_type() != NULL && tt->is_string_type())) | |
2399 { | |
2400 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune) | |
2401 this->flows(dst, src); | |
2402 break; | |
2403 } | |
2404 // Conversion preserves input value. | |
2405 Expression* underlying = tce->expr(); | |
2406 this->assign(dst, Node::make_node(underlying)); | |
2407 } | |
2408 break; | |
1933 | 2409 |
1934 case Expression::EXPRESSION_FIELD_REFERENCE: | 2410 case Expression::EXPRESSION_FIELD_REFERENCE: |
1935 { | 2411 { |
1936 // A non-pointer can't escape from a struct. | 2412 // A non-pointer can't escape from a struct. |
1937 if (!e->type()->has_pointer()) | 2413 if (!e->type()->has_pointer()) |
1938 break; | 2414 break; |
1939 } | 2415 } |
1940 // Fall through. | 2416 // Fall through. |
1941 | 2417 |
1942 case Expression::EXPRESSION_CONVERSION: | |
1943 case Expression::EXPRESSION_TYPE_GUARD: | 2418 case Expression::EXPRESSION_TYPE_GUARD: |
1944 case Expression::EXPRESSION_ARRAY_INDEX: | 2419 case Expression::EXPRESSION_ARRAY_INDEX: |
1945 case Expression::EXPRESSION_STRING_INDEX: | 2420 case Expression::EXPRESSION_STRING_INDEX: |
1946 { | 2421 { |
1947 Expression* left = NULL; | 2422 Expression* left = NULL; |
1954 // DST = (*x).f | 2429 // DST = (*x).f |
1955 this->flows(dst, src); | 2430 this->flows(dst, src); |
1956 break; | 2431 break; |
1957 } | 2432 } |
1958 } | 2433 } |
1959 else if (e->conversion_expression() != NULL) | |
1960 left = e->conversion_expression()->expr(); | |
1961 else if (e->type_guard_expression() != NULL) | 2434 else if (e->type_guard_expression() != NULL) |
1962 left = e->type_guard_expression()->expr(); | 2435 left = e->type_guard_expression()->expr(); |
1963 else if (e->array_index_expression() != NULL) | 2436 else if (e->array_index_expression() != NULL) |
1964 { | 2437 { |
1965 Array_index_expression* aie = e->array_index_expression(); | 2438 Array_index_expression* aie = e->array_index_expression(); |
1966 if (e->type()->is_slice_type()) | 2439 if (aie->end() != NULL) |
1967 left = aie->array(); | 2440 // slicing |
2441 if (aie->array()->type()->is_slice_type()) | |
2442 left = aie->array(); | |
2443 else | |
2444 { | |
2445 // slicing an array | |
2446 // The gc compiler has an implicit address operator. | |
2447 go_assert(src->child() != NULL); | |
2448 this->assign(dst, src->child()); | |
2449 break; | |
2450 } | |
1968 else if (!aie->array()->type()->is_slice_type()) | 2451 else if (!aie->array()->type()->is_slice_type()) |
1969 { | 2452 { |
1970 // Indexing an array preserves the input value. | 2453 // Indexing an array preserves the input value. |
1971 Node* array_node = Node::make_node(aie->array()); | 2454 Node* array_node = Node::make_node(aie->array()); |
1972 this->assign(dst, array_node); | 2455 this->assign(dst, array_node); |
1979 } | 2462 } |
1980 } | 2463 } |
1981 else if (e->string_index_expression() != NULL) | 2464 else if (e->string_index_expression() != NULL) |
1982 { | 2465 { |
1983 String_index_expression* sie = e->string_index_expression(); | 2466 String_index_expression* sie = e->string_index_expression(); |
1984 if (e->type()->is_slice_type()) | 2467 if (e->type()->is_string_type()) |
2468 // slicing | |
1985 left = sie->string(); | 2469 left = sie->string(); |
1986 else if (!sie->string()->type()->is_slice_type()) | |
1987 { | |
1988 // Indexing a string preserves the input value. | |
1989 Node* string_node = Node::make_node(sie->string()); | |
1990 this->assign(dst, string_node); | |
1991 break; | |
1992 } | |
1993 else | 2470 else |
1994 { | 2471 { |
1995 this->flows(dst, src); | 2472 this->flows(dst, src); |
1996 break; | 2473 break; |
1997 } | 2474 } |
2010 switch (e->binary_expression()->op()) | 2487 switch (e->binary_expression()->op()) |
2011 { | 2488 { |
2012 case OPERATOR_PLUS: | 2489 case OPERATOR_PLUS: |
2013 case OPERATOR_MINUS: | 2490 case OPERATOR_MINUS: |
2014 case OPERATOR_XOR: | 2491 case OPERATOR_XOR: |
2492 case OPERATOR_OR: | |
2015 case OPERATOR_MULT: | 2493 case OPERATOR_MULT: |
2016 case OPERATOR_DIV: | 2494 case OPERATOR_DIV: |
2017 case OPERATOR_MOD: | 2495 case OPERATOR_MOD: |
2018 case OPERATOR_LSHIFT: | 2496 case OPERATOR_LSHIFT: |
2019 case OPERATOR_RSHIFT: | 2497 case OPERATOR_RSHIFT: |
2061 break; | 2539 break; |
2062 | 2540 |
2063 case Expression::EXPRESSION_TEMPORARY_REFERENCE: | 2541 case Expression::EXPRESSION_TEMPORARY_REFERENCE: |
2064 { | 2542 { |
2065 Statement* temp = e->temporary_reference_expression()->statement(); | 2543 Statement* temp = e->temporary_reference_expression()->statement(); |
2066 if (temp != NULL | 2544 this->assign(dst, Node::make_node(temp)); |
2067 && temp->temporary_statement()->init() != NULL) | |
2068 { | |
2069 Expression* init = temp->temporary_statement()->init(); | |
2070 Node* init_node = Node::make_node(init); | |
2071 this->assign(dst, init_node); | |
2072 } | |
2073 } | 2545 } |
2074 break; | 2546 break; |
2075 | 2547 |
2076 default: | 2548 default: |
2077 // TODO(cmang): Add debug info here; this should not be reachable. | 2549 // TODO(cmang): Add debug info here; this should not be reachable. |
2078 // For now, just to be conservative, we'll just say dst flows to src. | 2550 // For now, just to be conservative, we'll just say dst flows to src. |
2079 break; | 2551 break; |
2080 } | 2552 } |
2081 } | 2553 } |
2554 else if (src->statement() != NULL && src->statement()->temporary_statement() != NULL) | |
2555 this->flows(dst, src); | |
2082 } | 2556 } |
2083 | 2557 |
2084 // Model the assignment of DST to an indirection of SRC. | 2558 // Model the assignment of DST to an indirection of SRC. |
2085 | 2559 |
2086 void | 2560 void |
2099 case Expression::EXPRESSION_IOTA: | 2573 case Expression::EXPRESSION_IOTA: |
2100 // No need to try indirections on literal values | 2574 // No need to try indirections on literal values |
2101 // or numeric constants. | 2575 // or numeric constants. |
2102 return; | 2576 return; |
2103 | 2577 |
2104 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION: | |
2105 case Expression::EXPRESSION_SLICE_CONSTRUCTION: | |
2106 case Expression::EXPRESSION_STRUCT_CONSTRUCTION: | |
2107 { | |
2108 // Dereferencing an array, slice, or struct is like accessing each | |
2109 // of its values. In this situation, we model the flow from src to | |
2110 // dst where src is one of the above as a flow from each of src's | |
2111 // values to dst. | |
2112 Expression* e = src->expr(); | |
2113 Expression_list* vals = NULL; | |
2114 if (e->slice_literal() != NULL) | |
2115 vals = e->slice_literal()->vals(); | |
2116 else if (e->array_literal() != NULL) | |
2117 vals = e->array_literal()->vals(); | |
2118 else | |
2119 vals = e->struct_literal()->vals(); | |
2120 | |
2121 if (vals != NULL) | |
2122 { | |
2123 for (Expression_list::const_iterator p = vals->begin(); | |
2124 p != vals->end(); | |
2125 ++p) | |
2126 { | |
2127 if ((*p) != NULL) | |
2128 this->assign(dst, Node::make_node(*p)); | |
2129 } | |
2130 } | |
2131 } | |
2132 return; | |
2133 | |
2134 default: | 2578 default: |
2135 break; | 2579 break; |
2136 } | 2580 } |
2137 } | 2581 } |
2138 | 2582 |
2167 break; | 2611 break; |
2168 } | 2612 } |
2169 } | 2613 } |
2170 | 2614 |
2171 if (this->context_->gogo()->debug_escape_level() > 2) | 2615 if (this->context_->gogo()->debug_escape_level() > 2) |
2172 go_inform(src->location(), "assignfromtag:: src= em=%s", | 2616 go_inform(src->location(), "assignfromtag:: src=%s em=%s", |
2617 src->ast_format(context_->gogo()).c_str(), | |
2173 Escape_note::make_tag(enc).c_str()); | 2618 Escape_note::make_tag(enc).c_str()); |
2174 | 2619 |
2175 if (enc == Node::ESCAPE_UNKNOWN) | 2620 if (enc == Node::ESCAPE_UNKNOWN) |
2176 { | 2621 { |
2177 // Lost track of the value. | 2622 // Lost track of the value. |
2220 | 2665 |
2221 void | 2666 void |
2222 Escape_analysis_assign::flows(Node* dst, Node* src) | 2667 Escape_analysis_assign::flows(Node* dst, Node* src) |
2223 { | 2668 { |
2224 // Don't bother capturing the flow from scalars. | 2669 // Don't bother capturing the flow from scalars. |
2225 if (src->expr() != NULL | 2670 if (src->type() != NULL && !src->type()->has_pointer()) |
2226 && !src->expr()->type()->has_pointer()) | |
2227 return; | 2671 return; |
2228 | 2672 |
2229 // Don't confuse a blank identifier with the sink. | 2673 // Don't confuse a blank identifier with the sink. |
2230 if (dst->is_sink() && dst != this->context_->sink()) | 2674 if (dst->is_sink() && dst != this->context_->sink()) |
2231 return; | 2675 return; |
2232 | 2676 |
2233 Node::Escape_state* dst_state = dst->state(this->context_, NULL); | 2677 Node::Escape_state* dst_state = dst->state(this->context_, NULL); |
2234 Node::Escape_state* src_state = src->state(this->context_, NULL); | 2678 Node::Escape_state* src_state = src->state(this->context_, NULL); |
2235 if (dst == src | 2679 if (dst == src |
2236 || dst_state == src_state | 2680 || dst_state == src_state |
2237 || dst_state->flows.find(src) != dst_state->flows.end() | 2681 || dst_state->flows.find(src) != dst_state->flows.end()) |
2238 || src_state->flows.find(dst) != src_state->flows.end()) | |
2239 return; | 2682 return; |
2240 | 2683 |
2241 Gogo* gogo = this->context_->gogo(); | 2684 Gogo* gogo = this->context_->gogo(); |
2242 if (gogo->debug_escape_level() > 2) | 2685 if (gogo->debug_escape_level() > 2) |
2243 go_inform(Linemap::unknown_location(), "flows:: %s <- %s", | 2686 go_inform(Linemap::unknown_location(), "flows:: %s <- %s", |
2269 p != res->end(); | 2712 p != res->end(); |
2270 ++p) | 2713 ++p) |
2271 { | 2714 { |
2272 Node* res_node = Node::make_node(*p); | 2715 Node* res_node = Node::make_node(*p); |
2273 Node::Escape_state* res_state = res_node->state(context, fn); | 2716 Node::Escape_state* res_state = res_node->state(context, fn); |
2717 res_state->fn = fn; | |
2274 res_state->loop_depth = 0; | 2718 res_state->loop_depth = 0; |
2275 | 2719 |
2276 // If this set of functions is recursive, we lose track of the return values. | 2720 // If this set of functions is recursive, we lose track of the return values. |
2277 // Just say that the result flows to the sink. | 2721 // Just say that the result flows to the sink. |
2278 if (context->recursive()) | 2722 if (context->recursive()) |
2297 | 2741 |
2298 Named_object* param_no = callee_bindings->lookup_local(p->name()); | 2742 Named_object* param_no = callee_bindings->lookup_local(p->name()); |
2299 go_assert(param_no != NULL); | 2743 go_assert(param_no != NULL); |
2300 Node* param_node = Node::make_node(param_no); | 2744 Node* param_node = Node::make_node(param_no); |
2301 Node::Escape_state* param_state = param_node->state(context, fn); | 2745 Node::Escape_state* param_state = param_node->state(context, fn); |
2746 param_state->fn = fn; | |
2302 param_state->loop_depth = 1; | 2747 param_state->loop_depth = 1; |
2303 | 2748 |
2304 if (!p->type()->has_pointer()) | 2749 if (!p->type()->has_pointer()) |
2305 continue; | 2750 continue; |
2306 | 2751 |
2307 // External function? Parameters must escape unless //go:noescape is set. | 2752 // External function? Parameters must escape unless //go:noescape is set. |
2308 // TODO(cmang): Implement //go:noescape directive. | 2753 // TODO(cmang): Implement //go:noescape directive. |
2309 if (fn->package() != NULL) | 2754 if (fn->package() != NULL) |
2310 param_node->set_encoding(Node::ESCAPE_HEAP); | 2755 param_node->set_encoding(Node::ESCAPE_HEAP); |
2311 else | 2756 else |
2312 param_node->set_encoding(Node::ESCAPE_NONE); | 2757 { |
2313 | 2758 param_node->set_encoding(Node::ESCAPE_NONE); |
2314 // TODO(cmang): Track this node in no_escape list. | 2759 context->track(param_node); |
2760 } | |
2315 } | 2761 } |
2316 | 2762 |
2317 Escape_analysis_loop el; | 2763 Escape_analysis_loop el; |
2318 fn->func_value()->traverse(&el); | 2764 fn->func_value()->traverse(&el); |
2319 | 2765 |
2430 if (dst->expr() != NULL && dst->expr()->var_expression() != NULL) | 2876 if (dst->expr() != NULL && dst->expr()->var_expression() != NULL) |
2431 dst_no = dst->expr()->var_expression()->named_object(); | 2877 dst_no = dst->expr()->var_expression()->named_object(); |
2432 else | 2878 else |
2433 dst_no = dst->object(); | 2879 dst_no = dst->object(); |
2434 bool dst_is_result = dst_no != NULL && dst_no->is_result_variable(); | 2880 bool dst_is_result = dst_no != NULL && dst_no->is_result_variable(); |
2881 Node::Escape_state* dst_state = dst->state(this->context_, NULL); | |
2435 | 2882 |
2436 if (src_is_param | 2883 if (src_is_param |
2437 && dst_is_result | 2884 && dst_is_result |
2438 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_SCOPE) | 2885 && src_state->fn == dst_state->fn |
2886 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP) | |
2439 && dst->encoding() != Node::ESCAPE_HEAP) | 2887 && dst->encoding() != Node::ESCAPE_HEAP) |
2440 { | 2888 { |
2441 // This case handles: | 2889 // This case handles: |
2442 // 1. return in | 2890 // 1. return in |
2443 // 2. return &in | 2891 // 2. return &in |
2444 // 3. tmp := in; return &tmp | 2892 // 3. tmp := in; return &tmp |
2445 // 4. return *in | 2893 // 4. return *in |
2446 if (debug_level != 0) | 2894 if (debug_level != 0) |
2447 { | 2895 { |
2448 if (debug_level == 1) | 2896 if (debug_level == 1) |
2449 go_inform(src->location(), | 2897 go_inform(src->definition_location(), |
2450 "leaking param: %s to result %s level=%d", | 2898 "leaking param: %s to result %s level=%d", |
2451 src->ast_format(gogo).c_str(), | 2899 src->ast_format(gogo).c_str(), |
2452 dst->ast_format(gogo).c_str(), | 2900 dst->ast_format(gogo).c_str(), |
2453 level.value()); | 2901 level.value()); |
2454 else | 2902 else |
2455 go_inform(src->location(), | 2903 go_inform(src->definition_location(), |
2456 "leaking param: %s to result %s level={%d %d}", | 2904 "leaking param: %s to result %s level={%d %d}", |
2457 src->ast_format(gogo).c_str(), | 2905 src->ast_format(gogo).c_str(), |
2458 dst->ast_format(gogo).c_str(), | 2906 dst->ast_format(gogo).c_str(), |
2459 level.value(), level.suffix_value()); | 2907 level.value(), level.suffix_value()); |
2460 } | 2908 } |
2484 // If parameter content escape to heap, set ESCAPE_CONTENT_ESCAPES. | 2932 // If parameter content escape to heap, set ESCAPE_CONTENT_ESCAPES. |
2485 // Note minor confusion around escape from pointer-to-struct vs | 2933 // Note minor confusion around escape from pointer-to-struct vs |
2486 // escape from struct. | 2934 // escape from struct. |
2487 if (src_is_param | 2935 if (src_is_param |
2488 && dst->encoding() == Node::ESCAPE_HEAP | 2936 && dst->encoding() == Node::ESCAPE_HEAP |
2489 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_SCOPE) | 2937 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP) |
2490 && level.value() > 0) | 2938 && level.value() > 0) |
2491 { | 2939 { |
2492 int enc = | 2940 int enc = |
2493 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), | 2941 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), |
2494 Node::ESCAPE_NONE); | 2942 Node::ESCAPE_NONE); |
2495 src->set_encoding(enc); | 2943 src->set_encoding(enc); |
2496 if (debug_level != 0) | 2944 if (debug_level != 0) |
2497 go_inform(src->location(), "mark escaped content: %s", | 2945 go_inform(src->definition_location(), "mark escaped content: %s", |
2498 src->ast_format(gogo).c_str()); | 2946 src->ast_format(gogo).c_str()); |
2499 } | 2947 } |
2500 | 2948 |
2501 // A src object leaks if its value or address is assigned to a dst object | 2949 // A src object leaks if its value or address is assigned to a dst object |
2502 // in a different scope (at a different loop depth). | 2950 // in a different scope (at a different loop depth). |
2503 Node::Escape_state* dst_state = dst->state(this->context_, NULL); | |
2504 bool src_leaks = (level.value() <= 0 | 2951 bool src_leaks = (level.value() <= 0 |
2505 && level.suffix_value() <= 0 | 2952 && level.suffix_value() <= 0 |
2506 && dst_state->loop_depth < mod_loop_depth); | 2953 && dst_state->loop_depth < mod_loop_depth); |
2954 src_leaks = src_leaks || (level.value() <= 0 | |
2955 && (dst->encoding() & ESCAPE_MASK) == Node::ESCAPE_HEAP); | |
2956 // old src encoding, used to prevent duplicate error messages | |
2957 int osrcesc = src->encoding(); | |
2507 | 2958 |
2508 if (src_is_param | 2959 if (src_is_param |
2509 && (src_leaks || dst_state->loop_depth < 0) | 2960 && (src_leaks || dst_state->loop_depth < 0) |
2510 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_SCOPE)) | 2961 && (src->encoding() & ESCAPE_MASK) < int(Node::ESCAPE_HEAP)) |
2511 { | 2962 { |
2512 if (level.suffix_value() > 0) | 2963 if (level.suffix_value() > 0) |
2513 { | 2964 { |
2514 int enc = | 2965 int enc = |
2515 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), | 2966 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), |
2516 Node::ESCAPE_NONE); | 2967 Node::ESCAPE_NONE); |
2517 src->set_encoding(enc); | 2968 src->set_encoding(enc); |
2969 if (debug_level != 0 && osrcesc != src->encoding()) | |
2970 go_inform(src->definition_location(), "leaking param content: %s", | |
2971 src->ast_format(gogo).c_str()); | |
2972 } | |
2973 else | |
2974 { | |
2518 if (debug_level != 0) | 2975 if (debug_level != 0) |
2519 go_inform(src->location(), "leaking param content: %s", | 2976 go_inform(src->definition_location(), "leaking param: %s", |
2520 src->ast_format(gogo).c_str()); | 2977 src->ast_format(gogo).c_str()); |
2521 } | 2978 src->set_encoding(Node::ESCAPE_HEAP); |
2522 else | |
2523 { | |
2524 if (debug_level != 0) | |
2525 go_inform(src->location(), "leaking param"); | |
2526 src->set_encoding(Node::ESCAPE_SCOPE); | |
2527 } | 2979 } |
2528 } | 2980 } |
2529 else if (src->expr() != NULL) | 2981 else if (src->expr() != NULL) |
2530 { | 2982 { |
2531 Expression* e = src->expr(); | 2983 Expression* e = src->expr(); |
2555 // to the heap. | 3007 // to the heap. |
2556 underlying->address_taken(src_leaks); | 3008 underlying->address_taken(src_leaks); |
2557 if (src_leaks) | 3009 if (src_leaks) |
2558 { | 3010 { |
2559 src->set_encoding(Node::ESCAPE_HEAP); | 3011 src->set_encoding(Node::ESCAPE_HEAP); |
2560 if (debug_level != 0) | 3012 if (osrcesc != src->encoding()) |
2561 { | 3013 { |
2562 go_inform(underlying->location(), "moved to heap: %s", | 3014 move_to_heap(gogo, underlying); |
2563 underlying_node->ast_format(gogo).c_str()); | 3015 if (debug_level > 1) |
2564 | 3016 go_inform(src->location(), |
2565 if (debug_level > 1) | 3017 "%s escapes to heap, level={%d %d}, " |
2566 go_inform(src->location(), | 3018 "dst.eld=%d, src.eld=%d", |
2567 "%s escapes to heap, level={%d %d}, " | 3019 src->ast_format(gogo).c_str(), level.value(), |
2568 "dst.eld=%d, src.eld=%d", | 3020 level.suffix_value(), dst_state->loop_depth, |
2569 src->ast_format(gogo).c_str(), level.value(), | 3021 mod_loop_depth); |
2570 level.suffix_value(), dst_state->loop_depth, | 3022 else if (debug_level > 0) |
2571 mod_loop_depth); | 3023 go_inform(src->location(), "%s escapes to heap", |
2572 else | 3024 src->ast_format(gogo).c_str()); |
2573 go_inform(src->location(), "%s escapes to heap", | 3025 } |
2574 src->ast_format(gogo).c_str()); | |
2575 } | |
2576 | 3026 |
2577 this->flood(level.decrease(), dst, | 3027 this->flood(level.decrease(), dst, |
2578 underlying_node, mod_loop_depth); | 3028 underlying_node, mod_loop_depth); |
2579 extra_loop_depth = mod_loop_depth; | 3029 extra_loop_depth = mod_loop_depth; |
2580 } | 3030 } |
2598 } | 3048 } |
2599 } | 3049 } |
2600 if (src_leaks) | 3050 if (src_leaks) |
2601 { | 3051 { |
2602 src->set_encoding(Node::ESCAPE_HEAP); | 3052 src->set_encoding(Node::ESCAPE_HEAP); |
2603 if (debug_level != 0) | 3053 if (debug_level != 0 && osrcesc != src->encoding()) |
2604 go_inform(src->location(), "%s escapes to heap", | 3054 go_inform(src->location(), "%s escapes to heap", |
2605 src->ast_format(gogo).c_str()); | 3055 src->ast_format(gogo).c_str()); |
2606 extra_loop_depth = mod_loop_depth; | 3056 extra_loop_depth = mod_loop_depth; |
2607 } | 3057 } |
2608 } | 3058 } |
2609 else if (e->call_expression() != NULL) | 3059 else if (e->call_expression() != NULL) |
2610 { | 3060 { |
2611 Call_expression* call = e->call_expression(); | 3061 Call_expression* call = e->call_expression(); |
2612 if (call->fn()->func_expression() != NULL) | 3062 if (call->is_builtin()) |
2613 { | 3063 { |
2614 Func_expression* func = call->fn()->func_expression(); | 3064 Builtin_call_expression* bce = call->builtin_call_expression(); |
2615 if (func->is_runtime_function()) | 3065 if (bce->code() == Builtin_call_expression::BUILTIN_APPEND) |
2616 { | 3066 { |
2617 switch (func->runtime_code()) | 3067 // Propagate escape information to appendee. |
2618 { | 3068 Expression* appendee = call->args()->front(); |
2619 case Runtime::GROWSLICE: | 3069 this->flood(level, dst, Node::make_node(appendee), -1); |
2620 { | 3070 } |
2621 // Propagate escape information to appendee. | 3071 } |
2622 Expression* appendee = call->args()->front(); | 3072 else if (call->fn()->func_expression() != NULL |
2623 this->flood(level, dst, Node::make_node(appendee), -1); | 3073 && call->fn()->func_expression()->is_runtime_function()) |
2624 } | 3074 { |
2625 break; | 3075 switch (call->fn()->func_expression()->runtime_code()) |
2626 | 3076 { |
2627 case Runtime::MAKECHAN: | 3077 case Runtime::MAKECHAN: |
2628 case Runtime::MAKEMAP: | 3078 case Runtime::MAKECHAN64: |
2629 case Runtime::MAKESLICE: | 3079 case Runtime::MAKEMAP: |
2630 case Runtime::MAKESLICE64: | 3080 case Runtime::MAKESLICE: |
2631 case Runtime::SLICEBYTETOSTRING: | 3081 case Runtime::MAKESLICE64: |
2632 case Runtime::SLICERUNETOSTRING: | 3082 if (src_leaks) |
2633 case Runtime::STRINGTOSLICEBYTE: | 3083 { |
2634 case Runtime::STRINGTOSLICERUNE: | 3084 src->set_encoding(Node::ESCAPE_HEAP); |
2635 case Runtime::CONCATSTRINGS: | 3085 if (debug_level != 0 && osrcesc != src->encoding()) |
2636 case Runtime::CONCATSTRING2: | 3086 go_inform(src->location(), "%s escapes to heap", |
2637 case Runtime::CONCATSTRING3: | 3087 src->ast_format(gogo).c_str()); |
2638 case Runtime::CONCATSTRING4: | 3088 extra_loop_depth = mod_loop_depth; |
2639 case Runtime::CONCATSTRING5: | 3089 } |
2640 case Runtime::CONSTRUCT_MAP: | 3090 break; |
2641 case Runtime::INTSTRING: | 3091 |
2642 case Runtime::REQUIREITAB: | 3092 default: |
2643 // All runtime calls that involve allocation of memory | 3093 break; |
2644 // except new. Runtime::NEW gets lowered into an | 3094 } |
2645 // allocation expression. | 3095 } |
2646 if (src_leaks) | 3096 else if (src_state->retvals.size() > 0) |
2647 { | 3097 { |
2648 src->set_encoding(Node::ESCAPE_HEAP); | 3098 // In this case a link went directly to a call, but should really go |
2649 if (debug_level != 0) | 3099 // to the dummy .outN outputs that were created for the call that |
2650 go_inform(src->location(), "%s escapes to heap", | 3100 // themselves link to the inputs with levels adjusted. |
2651 src->ast_format(gogo).c_str()); | 3101 // See e.g. #10466. |
2652 extra_loop_depth = mod_loop_depth; | 3102 // This can only happen with functions returning a single result. |
2653 } | 3103 go_assert(src_state->retvals.size() == 1); |
2654 break; | 3104 if (debug_level > 2) |
2655 | 3105 go_inform(src->location(), "[%d] dst %s escwalk replace src: %s with %s", |
2656 default: | 3106 this->context_->loop_depth(), |
2657 break; | 3107 dst->ast_format(gogo).c_str(), |
2658 } | 3108 src->ast_format(gogo).c_str(), |
2659 } | 3109 src_state->retvals[0]->ast_format(gogo).c_str()); |
2660 else if (src_leaks | 3110 src = src_state->retvals[0]; |
2661 && (func->closure() != NULL | 3111 src_state = src->state(this->context_, NULL); |
2662 || func->bound_method_expression() != NULL)) | 3112 } |
2663 { | |
2664 // A closure or bound method; we lost track of actual function | |
2665 // so if this leaks, this call must be done on the heap. | |
2666 src->set_encoding(Node::ESCAPE_HEAP); | |
2667 if (debug_level != 0) | |
2668 go_inform(src->location(), "%s escapes to heap", | |
2669 src->ast_format(gogo).c_str()); | |
2670 } | |
2671 } | |
2672 } | 3113 } |
2673 else if (e->allocation_expression() != NULL && src_leaks) | 3114 else if (e->allocation_expression() != NULL && src_leaks) |
2674 { | 3115 { |
2675 // Calls to Runtime::NEW get lowered into an allocation expression. | 3116 // Calls to Runtime::NEW get lowered into an allocation expression. |
2676 src->set_encoding(Node::ESCAPE_HEAP); | 3117 src->set_encoding(Node::ESCAPE_HEAP); |
2677 if (debug_level != 0) | 3118 if (debug_level != 0 && osrcesc != src->encoding()) |
2678 go_inform(src->location(), "%s escapes to heap", | 3119 go_inform(src->location(), "%s escapes to heap", |
2679 src->ast_format(gogo).c_str()); | 3120 src->ast_format(gogo).c_str()); |
2680 } | 3121 extra_loop_depth = mod_loop_depth; |
3122 } | |
3123 else if ((e->map_literal() != NULL | |
3124 || e->string_concat_expression() != NULL | |
3125 || (e->func_expression() != NULL && e->func_expression()->closure() != NULL) | |
3126 || e->bound_method_expression() != NULL) | |
3127 && src_leaks) | |
3128 { | |
3129 src->set_encoding(Node::ESCAPE_HEAP); | |
3130 if (debug_level != 0 && osrcesc != src->encoding()) | |
3131 go_inform(src->location(), "%s escapes to heap", | |
3132 src->ast_format(gogo).c_str()); | |
3133 extra_loop_depth = mod_loop_depth; | |
3134 } | |
3135 else if (e->conversion_expression() != NULL && src_leaks) | |
3136 { | |
3137 Type_conversion_expression* tce = e->conversion_expression(); | |
3138 Type* ft = tce->expr()->type(); | |
3139 Type* tt = tce->type(); | |
3140 if ((ft->is_string_type() && tt->is_slice_type()) | |
3141 || (ft->is_slice_type() && tt->is_string_type()) | |
3142 || (ft->integer_type() != NULL && tt->is_string_type())) | |
3143 { | |
3144 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune) | |
3145 src->set_encoding(Node::ESCAPE_HEAP); | |
3146 if (debug_level != 0 && osrcesc != src->encoding()) | |
3147 go_inform(src->location(), "%s escapes to heap", | |
3148 src->ast_format(gogo).c_str()); | |
3149 extra_loop_depth = mod_loop_depth; | |
3150 } | |
3151 } | |
3152 else if (e->array_index_expression() != NULL | |
3153 && !e->array_index_expression()->array()->type()->is_slice_type()) | |
3154 { | |
3155 Array_index_expression* aie = e->array_index_expression(); | |
3156 if (aie->end() != NULL) | |
3157 { | |
3158 // Slicing an array. | |
3159 // Flow its implicit address-of node to DST. | |
3160 this->flood(level, dst, src->child(), -1); | |
3161 } | |
3162 else | |
3163 { | |
3164 // Indexing an array. | |
3165 // An array element flowing to DST behaves like the array | |
3166 // flowing to DST. | |
3167 Expression* underlying = e->array_index_expression()->array(); | |
3168 Node* underlying_node = Node::make_node(underlying); | |
3169 this->flood(level, dst, underlying_node, -1); | |
3170 } | |
3171 } | |
2681 else if ((e->field_reference_expression() != NULL | 3172 else if ((e->field_reference_expression() != NULL |
2682 && e->field_reference_expression()->expr()->unary_expression() == NULL) | 3173 && e->field_reference_expression()->expr()->unary_expression() == NULL) |
2683 || e->type_guard_expression() != NULL | 3174 || e->type_guard_expression() != NULL |
2684 || (e->array_index_expression() != NULL | 3175 || (e->array_index_expression() != NULL |
2685 && e->type()->is_slice_type()) | 3176 && e->array_index_expression()->end() != NULL) |
2686 || (e->string_index_expression() != NULL | 3177 || (e->string_index_expression() != NULL |
2687 && e->type()->is_slice_type())) | 3178 && e->type()->is_string_type())) |
2688 { | 3179 { |
2689 Expression* underlying; | 3180 Expression* underlying; |
2690 if (e->field_reference_expression() != NULL) | 3181 if (e->field_reference_expression() != NULL) |
2691 underlying = e->field_reference_expression()->expr(); | 3182 underlying = e->field_reference_expression()->expr(); |
2692 else if (e->type_guard_expression() != NULL) | 3183 else if (e->type_guard_expression() != NULL) |
2711 { | 3202 { |
2712 underlying = e->field_reference_expression()->expr(); | 3203 underlying = e->field_reference_expression()->expr(); |
2713 underlying = underlying->unary_expression()->operand(); | 3204 underlying = underlying->unary_expression()->operand(); |
2714 } | 3205 } |
2715 else if (e->array_index_expression() != NULL) | 3206 else if (e->array_index_expression() != NULL) |
2716 { | 3207 underlying = e->array_index_expression()->array(); |
2717 underlying = e->array_index_expression()->array(); | |
2718 if (!underlying->type()->is_slice_type()) | |
2719 { | |
2720 Node* underlying_node = Node::make_node(underlying); | |
2721 this->flood(level, dst, underlying_node, 1); | |
2722 } | |
2723 } | |
2724 else if (e->map_index_expression() != NULL) | 3208 else if (e->map_index_expression() != NULL) |
2725 underlying = e->map_index_expression()->map(); | 3209 underlying = e->map_index_expression()->map(); |
2726 else | 3210 else |
2727 underlying = e->unary_expression()->operand(); | 3211 underlying = e->unary_expression()->operand(); |
2728 | 3212 |
2729 // Increase the level for a dereference. | 3213 // Increase the level for a dereference. |
2730 Node* underlying_node = Node::make_node(underlying); | 3214 Node* underlying_node = Node::make_node(underlying); |
2731 this->flood(level.increase(), dst, underlying_node, -1); | 3215 this->flood(level.increase(), dst, underlying_node, -1); |
2732 } | 3216 } |
2733 | 3217 else if (e->temporary_reference_expression() != NULL) |
2734 // TODO(cmang): Add case for Issue #10466. | 3218 { |
2735 } | 3219 Statement* t = e->temporary_reference_expression()->statement(); |
3220 this->flood(level, dst, Node::make_node(t), -1); | |
3221 } | |
3222 } | |
3223 else if (src->is_indirect()) | |
3224 // Increase the level for a dereference. | |
3225 this->flood(level.increase(), dst, src->child(), -1); | |
2736 | 3226 |
2737 level = level.copy(); | 3227 level = level.copy(); |
2738 for (std::set<Node*>::const_iterator p = src_state->flows.begin(); | 3228 for (std::set<Node*>::const_iterator p = src_state->flows.begin(); |
2739 p != src_state->flows.end(); | 3229 p != src_state->flows.end(); |
2740 ++p) | 3230 ++p) |
2747 // This is an implementation of gc/esc.go:escflood. | 3237 // This is an implementation of gc/esc.go:escflood. |
2748 | 3238 |
2749 void | 3239 void |
2750 Gogo::propagate_escape(Escape_context* context, Node* dst) | 3240 Gogo::propagate_escape(Escape_context* context, Node* dst) |
2751 { | 3241 { |
3242 if (dst->object() == NULL | |
3243 && (dst->expr() == NULL | |
3244 || (dst->expr()->var_expression() == NULL | |
3245 && dst->expr()->enclosed_var_expression() == NULL | |
3246 && dst->expr()->func_expression() == NULL))) | |
3247 return; | |
3248 | |
2752 Node::Escape_state* state = dst->state(context, NULL); | 3249 Node::Escape_state* state = dst->state(context, NULL); |
2753 Gogo* gogo = context->gogo(); | 3250 Gogo* gogo = context->gogo(); |
2754 if (gogo->debug_escape_level() > 1) | 3251 if (gogo->debug_escape_level() > 1) |
2755 go_inform(Linemap::unknown_location(), "escflood:%d: dst %s scope:%s[%d]", | 3252 go_inform(Linemap::unknown_location(), "escflood:%d: dst %s scope:%s[%d]", |
2756 context->flood_id(), dst->ast_format(gogo).c_str(), | 3253 context->flood_id(), dst->ast_format(gogo).c_str(), |
2786 void | 3283 void |
2787 Escape_analysis_tag::tag(Named_object* fn) | 3284 Escape_analysis_tag::tag(Named_object* fn) |
2788 { | 3285 { |
2789 // External functions are assumed unsafe | 3286 // External functions are assumed unsafe |
2790 // unless //go:noescape is given before the declaration. | 3287 // unless //go:noescape is given before the declaration. |
2791 if (fn->package() != NULL || !fn->is_function()) | 3288 if (fn->package() != NULL) |
2792 { | 3289 return; |
2793 // TODO(cmang): Implement //go:noescape directive for external functions; | 3290 |
2794 // mark input parameters as not escaping. | 3291 if (fn->is_function_declaration()) |
2795 return; | 3292 { |
2796 } | 3293 Function_declaration* fdcl = fn->func_declaration_value(); |
3294 if ((fdcl->pragmas() & GOPRAGMA_NOESCAPE) != 0) | |
3295 { | |
3296 Function_type* fntype = fdcl->type(); | |
3297 if (fntype->parameters() != NULL) | |
3298 { | |
3299 const Typed_identifier_list* til = fntype->parameters(); | |
3300 int i = 0; | |
3301 for (Typed_identifier_list::const_iterator p = til->begin(); | |
3302 p != til->end(); | |
3303 ++p, ++i) | |
3304 if (p->type()->has_pointer()) | |
3305 fntype->add_parameter_note(i, Node::ESCAPE_NONE); | |
3306 } | |
3307 } | |
3308 } | |
3309 | |
3310 if (!fn->is_function()) | |
3311 return; | |
2797 | 3312 |
2798 Function_type* fntype = fn->func_value()->type(); | 3313 Function_type* fntype = fn->func_value()->type(); |
2799 Bindings* bindings = fn->func_value()->block()->bindings(); | 3314 Bindings* bindings = fn->func_value()->block()->bindings(); |
2800 | 3315 |
2801 if (fntype->is_method() | 3316 if (fntype->is_method()) |
2802 && !fntype->receiver()->name().empty() | 3317 { |
2803 && !Gogo::is_sink_name(fntype->receiver()->name())) | 3318 if (fntype->receiver()->name().empty() |
2804 { | 3319 || Gogo::is_sink_name(fntype->receiver()->name())) |
2805 Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name()); | 3320 // Unnamed receiver is not used in the function body, does not escape. |
2806 go_assert(rcvr_no != NULL); | 3321 fntype->add_receiver_note(Node::ESCAPE_NONE); |
2807 Node* rcvr_node = Node::make_node(rcvr_no); | 3322 else |
2808 switch ((rcvr_node->encoding() & ESCAPE_MASK)) | 3323 { |
2809 { | 3324 Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name()); |
2810 case Node::ESCAPE_NONE: // not touched by flood | 3325 go_assert(rcvr_no != NULL); |
2811 case Node::ESCAPE_RETURN: | 3326 Node* rcvr_node = Node::make_node(rcvr_no); |
2812 if (fntype->receiver()->type()->has_pointer()) | 3327 switch ((rcvr_node->encoding() & ESCAPE_MASK)) |
2813 // Don't bother tagging for scalars. | 3328 { |
2814 fntype->add_receiver_note(rcvr_node->encoding()); | 3329 case Node::ESCAPE_NONE: // not touched by flood |
2815 break; | 3330 case Node::ESCAPE_RETURN: |
2816 | 3331 if (fntype->receiver()->type()->has_pointer()) |
2817 case Node::ESCAPE_HEAP: // flooded, moved to heap. | 3332 // Don't bother tagging for scalars. |
2818 case Node::ESCAPE_SCOPE: // flooded, value leaves scope. | 3333 fntype->add_receiver_note(rcvr_node->encoding()); |
2819 break; | 3334 break; |
2820 | 3335 |
2821 default: | 3336 case Node::ESCAPE_HEAP: // flooded, moved to heap. |
2822 break; | 3337 break; |
2823 } | 3338 |
3339 default: | |
3340 break; | |
3341 } | |
3342 } | |
2824 } | 3343 } |
2825 | 3344 |
2826 int i = 0; | 3345 int i = 0; |
2827 if (fntype->parameters() != NULL) | 3346 if (fntype->parameters() != NULL) |
2828 { | 3347 { |
2830 for (Typed_identifier_list::const_iterator p = til->begin(); | 3349 for (Typed_identifier_list::const_iterator p = til->begin(); |
2831 p != til->end(); | 3350 p != til->end(); |
2832 ++p, ++i) | 3351 ++p, ++i) |
2833 { | 3352 { |
2834 if (p->name().empty() || Gogo::is_sink_name(p->name())) | 3353 if (p->name().empty() || Gogo::is_sink_name(p->name())) |
2835 continue; | 3354 { |
3355 // Parameter not used in the function body, does not escape. | |
3356 if (p->type()->has_pointer()) | |
3357 fntype->add_parameter_note(i, Node::ESCAPE_NONE); | |
3358 continue; | |
3359 } | |
2836 | 3360 |
2837 Named_object* param_no = bindings->lookup(p->name()); | 3361 Named_object* param_no = bindings->lookup(p->name()); |
2838 go_assert(param_no != NULL); | 3362 go_assert(param_no != NULL); |
2839 Node* param_node = Node::make_node(param_no); | 3363 Node* param_node = Node::make_node(param_no); |
2840 switch ((param_node->encoding() & ESCAPE_MASK)) | 3364 switch ((param_node->encoding() & ESCAPE_MASK)) |
2845 // Don't bother tagging for scalars. | 3369 // Don't bother tagging for scalars. |
2846 fntype->add_parameter_note(i, param_node->encoding()); | 3370 fntype->add_parameter_note(i, param_node->encoding()); |
2847 break; | 3371 break; |
2848 | 3372 |
2849 case Node::ESCAPE_HEAP: // flooded, moved to heap. | 3373 case Node::ESCAPE_HEAP: // flooded, moved to heap. |
2850 case Node::ESCAPE_SCOPE: // flooded, value leaves scope. | |
2851 break; | 3374 break; |
2852 | 3375 |
2853 default: | 3376 default: |
2854 break; | 3377 break; |
2855 } | 3378 } |
2865 Gogo::tag_function(Escape_context* context, Named_object* fn) | 3388 Gogo::tag_function(Escape_context* context, Named_object* fn) |
2866 { | 3389 { |
2867 Escape_analysis_tag eat(context); | 3390 Escape_analysis_tag eat(context); |
2868 eat.tag(fn); | 3391 eat.tag(fn); |
2869 } | 3392 } |
3393 | |
3394 // Reclaim memory of escape analysis Nodes. | |
3395 | |
3396 void | |
3397 Gogo::reclaim_escape_nodes() | |
3398 { | |
3399 Node::reclaim_nodes(); | |
3400 } | |
3401 | |
3402 void | |
3403 Node::reclaim_nodes() | |
3404 { | |
3405 for (std::map<Named_object*, Node*>::iterator p = Node::objects.begin(); | |
3406 p != Node::objects.end(); | |
3407 ++p) | |
3408 delete p->second; | |
3409 Node::objects.clear(); | |
3410 | |
3411 for (std::map<Expression*, Node*>::iterator p = Node::expressions.begin(); | |
3412 p != Node::expressions.end(); | |
3413 ++p) | |
3414 delete p->second; | |
3415 Node::expressions.clear(); | |
3416 | |
3417 for (std::map<Statement*, Node*>::iterator p = Node::statements.begin(); | |
3418 p != Node::statements.end(); | |
3419 ++p) | |
3420 delete p->second; | |
3421 Node::statements.clear(); | |
3422 | |
3423 for (std::vector<Node*>::iterator p = Node::indirects.begin(); | |
3424 p != Node::indirects.end(); | |
3425 ++p) | |
3426 delete *p; | |
3427 Node::indirects.clear(); | |
3428 } |