github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/gc/esc.c (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Escape analysis. 6 7 #include <u.h> 8 #include <libc.h> 9 #include "go.h" 10 11 // Run analysis on minimal sets of mutually recursive functions 12 // or single non-recursive functions, bottom up. 13 // 14 // Finding these sets is finding strongly connected components 15 // in the static call graph. The algorithm for doing that is taken 16 // from Sedgewick, Algorithms, Second Edition, p. 482, with two 17 // adaptations. 18 // 19 // First, a hidden closure function (n->curfn != N) cannot be the 20 // root of a connected component. Refusing to use it as a root 21 // forces it into the component of the function in which it appears. 22 // The analysis assumes that closures and the functions in which they 23 // appear are analyzed together, so that the aliasing between their 24 // variables can be modeled more precisely. 25 // 26 // Second, each function becomes two virtual nodes in the graph, 27 // with numbers n and n+1. We record the function's node number as n 28 // but search from node n+1. If the search tells us that the component 29 // number (min) is n+1, we know that this is a trivial component: one function 30 // plus its closures. If the search tells us that the component number is 31 // n, then there was a path from node n+1 back to node n, meaning that 32 // the function set is mutually recursive. The escape analysis can be 33 // more precise when analyzing a single non-recursive function than 34 // when analyzing a set of mutually recursive functions. 35 36 static NodeList *stack; 37 static uint32 visitgen; 38 static uint32 visit(Node*); 39 static uint32 visitcode(Node*, uint32); 40 static uint32 visitcodelist(NodeList*, uint32); 41 42 static void analyze(NodeList*, int); 43 44 enum 45 { 46 EscFuncUnknown = 0, 47 EscFuncPlanned, 48 EscFuncStarted, 49 EscFuncTagged, 50 }; 51 52 void 53 escapes(NodeList *all) 54 { 55 NodeList *l; 56 57 for(l=all; l; l=l->next) 58 l->n->walkgen = 0; 59 60 visitgen = 0; 61 for(l=all; l; l=l->next) 62 if(l->n->op == ODCLFUNC && l->n->curfn == N) 63 visit(l->n); 64 65 for(l=all; l; l=l->next) 66 l->n->walkgen = 0; 67 } 68 69 static uint32 70 visit(Node *n) 71 { 72 uint32 min, recursive; 73 NodeList *l, *block; 74 75 if(n->walkgen > 0) { 76 // already visited 77 return n->walkgen; 78 } 79 80 visitgen++; 81 n->walkgen = visitgen; 82 visitgen++; 83 min = visitgen; 84 85 l = mal(sizeof *l); 86 l->next = stack; 87 l->n = n; 88 stack = l; 89 min = visitcodelist(n->nbody, min); 90 if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) { 91 // This node is the root of a strongly connected component. 92 93 // The original min passed to visitcodelist was n->walkgen+1. 94 // If visitcodelist found its way back to n->walkgen, then this 95 // block is a set of mutually recursive functions. 96 // Otherwise it's just a lone function that does not recurse. 97 recursive = min == n->walkgen; 98 99 // Remove connected component from stack. 100 // Mark walkgen so that future visits return a large number 101 // so as not to affect the caller's min. 102 block = stack; 103 for(l=stack; l->n != n; l=l->next) 104 l->n->walkgen = (uint32)~0U; 105 n->walkgen = (uint32)~0U; 106 stack = l->next; 107 l->next = nil; 108 109 // Run escape analysis on this set of functions. 110 analyze(block, recursive); 111 } 112 113 return min; 114 } 115 116 static uint32 117 visitcodelist(NodeList *l, uint32 min) 118 { 119 for(; l; l=l->next) 120 min = visitcode(l->n, min); 121 return min; 122 } 123 124 static uint32 125 visitcode(Node *n, uint32 min) 126 { 127 Node *fn; 128 uint32 m; 129 130 if(n == N) 131 return min; 132 133 min = visitcodelist(n->ninit, min); 134 min = visitcode(n->left, min); 135 min = visitcode(n->right, min); 136 min = visitcodelist(n->list, min); 137 min = visitcode(n->ntest, min); 138 min = visitcode(n->nincr, min); 139 min = visitcodelist(n->nbody, min); 140 min = visitcodelist(n->nelse, min); 141 min = visitcodelist(n->rlist, min); 142 143 if(n->op == OCALLFUNC || n->op == OCALLMETH) { 144 fn = n->left; 145 if(n->op == OCALLMETH) 146 fn = n->left->right->sym->def; 147 if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody) 148 if((m = visit(fn->defn)) < min) 149 min = m; 150 } 151 152 if(n->op == OCLOSURE) 153 if((m = visit(n->closure)) < min) 154 min = m; 155 156 return min; 157 } 158 159 // An escape analysis pass for a set of functions. 160 // 161 // First escfunc, esc and escassign recurse over the ast of each 162 // function to dig out flow(dst,src) edges between any 163 // pointer-containing nodes and store them in dst->escflowsrc. For 164 // variables assigned to a variable in an outer scope or used as a 165 // return value, they store a flow(theSink, src) edge to a fake node 166 // 'the Sink'. For variables referenced in closures, an edge 167 // flow(closure, &var) is recorded and the flow of a closure itself to 168 // an outer scope is tracked the same way as other variables. 169 // 170 // Then escflood walks the graph starting at theSink and tags all 171 // variables of it can reach an & node as escaping and all function 172 // parameters it can reach as leaking. 173 // 174 // If a value's address is taken but the address does not escape, 175 // then the value can stay on the stack. If the value new(T) does 176 // not escape, then new(T) can be rewritten into a stack allocation. 177 // The same is true of slice literals. 178 // 179 // If optimizations are disabled (-N), this code is not used. 180 // Instead, the compiler assumes that any value whose address 181 // is taken without being immediately dereferenced 182 // needs to be moved to the heap, and new(T) and slice 183 // literals are always real allocations. 184 185 typedef struct EscState EscState; 186 187 static void escfunc(EscState*, Node *func); 188 static void esclist(EscState*, NodeList *l); 189 static void esc(EscState*, Node *n); 190 static void escloopdepthlist(EscState*, NodeList *l); 191 static void escloopdepth(EscState*, Node *n); 192 static void escassign(EscState*, Node *dst, Node *src); 193 static void esccall(EscState*, Node*); 194 static void escflows(EscState*, Node *dst, Node *src); 195 static void escflood(EscState*, Node *dst); 196 static void escwalk(EscState*, int level, Node *dst, Node *src); 197 static void esctag(EscState*, Node *func); 198 199 struct EscState { 200 // Fake node that all 201 // - return values and output variables 202 // - parameters on imported functions not marked 'safe' 203 // - assignments to global variables 204 // flow to. 205 Node theSink; 206 207 NodeList* dsts; // all dst nodes 208 int loopdepth; // for detecting nested loop scopes 209 int pdepth; // for debug printing in recursions. 210 int dstcount, edgecount; // diagnostic 211 NodeList* noesc; // list of possible non-escaping nodes, for printing 212 int recursive; // recursive function or group of mutually recursive functions. 213 }; 214 215 static Strlit *tags[16]; 216 217 static Strlit* 218 mktag(int mask) 219 { 220 Strlit *s; 221 char buf[40]; 222 223 switch(mask&EscMask) { 224 case EscNone: 225 case EscReturn: 226 break; 227 default: 228 fatal("escape mktag"); 229 } 230 231 mask >>= EscBits; 232 233 if(mask < nelem(tags) && tags[mask] != nil) 234 return tags[mask]; 235 236 snprint(buf, sizeof buf, "esc:0x%x", mask); 237 s = strlit(buf); 238 if(mask < nelem(tags)) 239 tags[mask] = s; 240 return s; 241 } 242 243 static int 244 parsetag(Strlit *note) 245 { 246 int em; 247 248 if(note == nil) 249 return EscUnknown; 250 if(strncmp(note->s, "esc:", 4) != 0) 251 return EscUnknown; 252 em = atoi(note->s + 4); 253 if (em == 0) 254 return EscNone; 255 return EscReturn | (em << EscBits); 256 } 257 258 static void 259 analyze(NodeList *all, int recursive) 260 { 261 NodeList *l; 262 EscState es, *e; 263 264 memset(&es, 0, sizeof es); 265 e = &es; 266 e->theSink.op = ONAME; 267 e->theSink.orig = &e->theSink; 268 e->theSink.class = PEXTERN; 269 e->theSink.sym = lookup(".sink"); 270 e->theSink.escloopdepth = -1; 271 e->recursive = recursive; 272 273 for(l=all; l; l=l->next) 274 if(l->n->op == ODCLFUNC) 275 l->n->esc = EscFuncPlanned; 276 277 // flow-analyze functions 278 for(l=all; l; l=l->next) 279 if(l->n->op == ODCLFUNC) 280 escfunc(e, l->n); 281 282 // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount); 283 284 // visit the upstream of each dst, mark address nodes with 285 // addrescapes, mark parameters unsafe 286 for(l = e->dsts; l; l=l->next) 287 escflood(e, l->n); 288 289 // for all top level functions, tag the typenodes corresponding to the param nodes 290 for(l=all; l; l=l->next) 291 if(l->n->op == ODCLFUNC) 292 esctag(e, l->n); 293 294 if(debug['m']) { 295 for(l=e->noesc; l; l=l->next) 296 if(l->n->esc == EscNone) 297 warnl(l->n->lineno, "%S %hN does not escape", 298 (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S, 299 l->n); 300 } 301 } 302 303 304 static void 305 escfunc(EscState *e, Node *func) 306 { 307 Node *savefn; 308 NodeList *ll; 309 int saveld; 310 311 // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":""); 312 313 if(func->esc != 1) 314 fatal("repeat escfunc %N", func->nname); 315 func->esc = EscFuncStarted; 316 317 saveld = e->loopdepth; 318 e->loopdepth = 1; 319 savefn = curfn; 320 curfn = func; 321 322 for(ll=curfn->dcl; ll; ll=ll->next) { 323 if(ll->n->op != ONAME) 324 continue; 325 switch (ll->n->class) { 326 case PPARAMOUT: 327 // out params are in a loopdepth between the sink and all local variables 328 ll->n->escloopdepth = 0; 329 break; 330 case PPARAM: 331 if(ll->n->type && !haspointers(ll->n->type)) 332 break; 333 if(curfn->nbody == nil && !curfn->noescape) 334 ll->n->esc = EscHeap; 335 else 336 ll->n->esc = EscNone; // prime for escflood later 337 e->noesc = list(e->noesc, ll->n); 338 ll->n->escloopdepth = 1; 339 break; 340 } 341 } 342 343 // in a mutually recursive group we lose track of the return values 344 if(e->recursive) 345 for(ll=curfn->dcl; ll; ll=ll->next) 346 if(ll->n->op == ONAME && ll->n->class == PPARAMOUT) 347 escflows(e, &e->theSink, ll->n); 348 349 escloopdepthlist(e, curfn->nbody); 350 esclist(e, curfn->nbody); 351 curfn = savefn; 352 e->loopdepth = saveld; 353 } 354 355 // Mark labels that have no backjumps to them as not increasing e->loopdepth. 356 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat 357 // and set it to one of the following two. Then in esc we'll clear it again. 358 static Label looping; 359 static Label nonlooping; 360 361 static void 362 escloopdepthlist(EscState *e, NodeList *l) 363 { 364 for(; l; l=l->next) 365 escloopdepth(e, l->n); 366 } 367 368 static void 369 escloopdepth(EscState *e, Node *n) 370 { 371 if(n == N) 372 return; 373 374 escloopdepthlist(e, n->ninit); 375 376 switch(n->op) { 377 case OLABEL: 378 if(!n->left || !n->left->sym) 379 fatal("esc:label without label: %+N", n); 380 // Walk will complain about this label being already defined, but that's not until 381 // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc 382 // if(n->left->sym->label != nil) 383 // fatal("escape analysis messed up analyzing label: %+N", n); 384 n->left->sym->label = &nonlooping; 385 break; 386 case OGOTO: 387 if(!n->left || !n->left->sym) 388 fatal("esc:goto without label: %+N", n); 389 // If we come past one that's uninitialized, this must be a (harmless) forward jump 390 // but if it's set to nonlooping the label must have preceded this goto. 391 if(n->left->sym->label == &nonlooping) 392 n->left->sym->label = &looping; 393 break; 394 } 395 396 escloopdepth(e, n->left); 397 escloopdepth(e, n->right); 398 escloopdepthlist(e, n->list); 399 escloopdepth(e, n->ntest); 400 escloopdepth(e, n->nincr); 401 escloopdepthlist(e, n->nbody); 402 escloopdepthlist(e, n->nelse); 403 escloopdepthlist(e, n->rlist); 404 405 } 406 407 static void 408 esclist(EscState *e, NodeList *l) 409 { 410 for(; l; l=l->next) 411 esc(e, l->n); 412 } 413 414 static void 415 esc(EscState *e, Node *n) 416 { 417 int lno; 418 NodeList *ll, *lr; 419 Node *a; 420 421 if(n == N) 422 return; 423 424 lno = setlineno(n); 425 426 if(n->op == OFOR || n->op == ORANGE) 427 e->loopdepth++; 428 429 esc(e, n->left); 430 esc(e, n->right); 431 esc(e, n->ntest); 432 esc(e, n->nincr); 433 esclist(e, n->ninit); 434 esclist(e, n->nbody); 435 esclist(e, n->nelse); 436 esclist(e, n->list); 437 esclist(e, n->rlist); 438 439 if(n->op == OFOR || n->op == ORANGE) 440 e->loopdepth--; 441 442 if(debug['m'] > 1) 443 print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth, 444 (curfn && curfn->nname) ? curfn->nname->sym : S, n); 445 446 switch(n->op) { 447 case ODCL: 448 // Record loop depth at declaration. 449 if(n->left) 450 n->left->escloopdepth = e->loopdepth; 451 break; 452 453 case OLABEL: 454 if(n->left->sym->label == &nonlooping) { 455 if(debug['m'] > 1) 456 print("%L:%N non-looping label\n", lineno, n); 457 } else if(n->left->sym->label == &looping) { 458 if(debug['m'] > 1) 459 print("%L: %N looping label\n", lineno, n); 460 e->loopdepth++; 461 } 462 // See case OLABEL in escloopdepth above 463 // else if(n->left->sym->label == nil) 464 // fatal("escape analysis missed or messed up a label: %+N", n); 465 466 n->left->sym->label = nil; 467 break; 468 469 case ORANGE: 470 // Everything but fixed array is a dereference. 471 if(isfixedarray(n->type) && n->list->next) 472 escassign(e, n->list->next->n, n->right); 473 break; 474 475 case OSWITCH: 476 if(n->ntest && n->ntest->op == OTYPESW) { 477 for(ll=n->list; ll; ll=ll->next) { // cases 478 // ntest->right is the argument of the .(type), 479 // ll->n->nname is the variable per case 480 escassign(e, ll->n->nname, n->ntest->right); 481 } 482 } 483 break; 484 485 case OAS: 486 case OASOP: 487 escassign(e, n->left, n->right); 488 break; 489 490 case OAS2: // x,y = a,b 491 if(count(n->list) == count(n->rlist)) 492 for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) 493 escassign(e, ll->n, lr->n); 494 break; 495 496 case OAS2RECV: // v, ok = <-ch 497 case OAS2MAPR: // v, ok = m[k] 498 case OAS2DOTTYPE: // v, ok = x.(type) 499 escassign(e, n->list->n, n->rlist->n); 500 break; 501 502 case OSEND: // ch <- x 503 escassign(e, &e->theSink, n->right); 504 break; 505 506 case ODEFER: 507 if(e->loopdepth == 1) // top level 508 break; 509 // arguments leak out of scope 510 // TODO: leak to a dummy node instead 511 // fallthrough 512 case OPROC: 513 // go f(x) - f and x escape 514 escassign(e, &e->theSink, n->left->left); 515 escassign(e, &e->theSink, n->left->right); // ODDDARG for call 516 for(ll=n->left->list; ll; ll=ll->next) 517 escassign(e, &e->theSink, ll->n); 518 break; 519 520 case OCALLMETH: 521 case OCALLFUNC: 522 case OCALLINTER: 523 esccall(e, n); 524 break; 525 526 case OAS2FUNC: // x,y = f() 527 // esccall already done on n->rlist->n. tie it's escretval to n->list 528 lr=n->rlist->n->escretval; 529 for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next) 530 escassign(e, ll->n, lr->n); 531 if(lr || ll) 532 fatal("esc oas2func"); 533 break; 534 535 case ORETURN: 536 ll=n->list; 537 if(count(n->list) == 1 && curfn->type->outtuple > 1) { 538 // OAS2FUNC in disguise 539 // esccall already done on n->list->n 540 // tie n->list->n->escretval to curfn->dcl PPARAMOUT's 541 ll = n->list->n->escretval; 542 } 543 544 for(lr = curfn->dcl; lr && ll; lr=lr->next) { 545 if (lr->n->op != ONAME || lr->n->class != PPARAMOUT) 546 continue; 547 escassign(e, lr->n, ll->n); 548 ll = ll->next; 549 } 550 if (ll != nil) 551 fatal("esc return list"); 552 break; 553 554 case OPANIC: 555 // Argument could leak through recover. 556 escassign(e, &e->theSink, n->left); 557 break; 558 559 case OAPPEND: 560 if(!n->isddd) 561 for(ll=n->list->next; ll; ll=ll->next) 562 escassign(e, &e->theSink, ll->n); // lose track of assign to dereference 563 break; 564 565 case OCONV: 566 case OCONVNOP: 567 case OCONVIFACE: 568 escassign(e, n, n->left); 569 break; 570 571 case OARRAYLIT: 572 if(isslice(n->type)) { 573 n->esc = EscNone; // until proven otherwise 574 e->noesc = list(e->noesc, n); 575 n->escloopdepth = e->loopdepth; 576 // Values make it to memory, lose track. 577 for(ll=n->list; ll; ll=ll->next) 578 escassign(e, &e->theSink, ll->n->right); 579 } else { 580 // Link values to array. 581 for(ll=n->list; ll; ll=ll->next) 582 escassign(e, n, ll->n->right); 583 } 584 break; 585 586 case OSTRUCTLIT: 587 // Link values to struct. 588 for(ll=n->list; ll; ll=ll->next) 589 escassign(e, n, ll->n->right); 590 break; 591 592 case OPTRLIT: 593 n->esc = EscNone; // until proven otherwise 594 e->noesc = list(e->noesc, n); 595 n->escloopdepth = e->loopdepth; 596 // Contents make it to memory, lose track. 597 escassign(e, &e->theSink, n->left); 598 break; 599 600 case OCALLPART: 601 n->esc = EscNone; // until proven otherwise 602 e->noesc = list(e->noesc, n); 603 n->escloopdepth = e->loopdepth; 604 // Contents make it to memory, lose track. 605 escassign(e, &e->theSink, n->left); 606 break; 607 608 case OMAPLIT: 609 n->esc = EscNone; // until proven otherwise 610 e->noesc = list(e->noesc, n); 611 n->escloopdepth = e->loopdepth; 612 // Keys and values make it to memory, lose track. 613 for(ll=n->list; ll; ll=ll->next) { 614 escassign(e, &e->theSink, ll->n->left); 615 escassign(e, &e->theSink, ll->n->right); 616 } 617 break; 618 619 case OCLOSURE: 620 // Link addresses of captured variables to closure. 621 for(ll=n->cvars; ll; ll=ll->next) { 622 if(ll->n->op == OXXX) // unnamed out argument; see dcl.c:/^funcargs 623 continue; 624 a = nod(OADDR, ll->n->closure, N); 625 a->lineno = ll->n->lineno; 626 a->escloopdepth = e->loopdepth; 627 typecheck(&a, Erv); 628 escassign(e, n, a); 629 } 630 // fallthrough 631 case OADDR: 632 case OMAKECHAN: 633 case OMAKEMAP: 634 case OMAKESLICE: 635 case ONEW: 636 n->escloopdepth = e->loopdepth; 637 n->esc = EscNone; // until proven otherwise 638 e->noesc = list(e->noesc, n); 639 break; 640 } 641 642 lineno = lno; 643 } 644 645 // Assert that expr somehow gets assigned to dst, if non nil. for 646 // dst==nil, any name node expr still must be marked as being 647 // evaluated in curfn. For expr==nil, dst must still be examined for 648 // evaluations inside it (e.g *f(x) = y) 649 static void 650 escassign(EscState *e, Node *dst, Node *src) 651 { 652 int lno; 653 NodeList *ll; 654 655 if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX) 656 return; 657 658 if(debug['m'] > 1) 659 print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth, 660 (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src); 661 662 setlineno(dst); 663 664 // Analyze lhs of assignment. 665 // Replace dst with e->theSink if we can't track it. 666 switch(dst->op) { 667 default: 668 dump("dst", dst); 669 fatal("escassign: unexpected dst"); 670 671 case OARRAYLIT: 672 case OCLOSURE: 673 case OCONV: 674 case OCONVIFACE: 675 case OCONVNOP: 676 case OMAPLIT: 677 case OSTRUCTLIT: 678 case OCALLPART: 679 break; 680 681 case ONAME: 682 if(dst->class == PEXTERN) 683 dst = &e->theSink; 684 break; 685 case ODOT: // treat "dst.x = src" as "dst = src" 686 escassign(e, dst->left, src); 687 return; 688 case OINDEX: 689 if(isfixedarray(dst->left->type)) { 690 escassign(e, dst->left, src); 691 return; 692 } 693 dst = &e->theSink; // lose track of dereference 694 break; 695 case OIND: 696 case ODOTPTR: 697 dst = &e->theSink; // lose track of dereference 698 break; 699 case OINDEXMAP: 700 // lose track of key and value 701 escassign(e, &e->theSink, dst->right); 702 dst = &e->theSink; 703 break; 704 } 705 706 lno = setlineno(src); 707 e->pdepth++; 708 709 switch(src->op) { 710 case OADDR: // dst = &x 711 case OIND: // dst = *x 712 case ODOTPTR: // dst = (*x).f 713 case ONAME: 714 case OPARAM: 715 case ODDDARG: 716 case OPTRLIT: 717 case OARRAYLIT: 718 case OMAPLIT: 719 case OSTRUCTLIT: 720 case OMAKECHAN: 721 case OMAKEMAP: 722 case OMAKESLICE: 723 case ONEW: 724 case OCLOSURE: 725 case OCALLPART: 726 escflows(e, dst, src); 727 break; 728 729 case OCALLMETH: 730 case OCALLFUNC: 731 case OCALLINTER: 732 // Flowing multiple returns to a single dst happens when 733 // analyzing "go f(g())": here g() flows to sink (issue 4529). 734 for(ll=src->escretval; ll; ll=ll->next) 735 escflows(e, dst, ll->n); 736 break; 737 738 case ODOT: 739 // A non-pointer escaping from a struct does not concern us. 740 if(src->type && !haspointers(src->type)) 741 break; 742 // fallthrough 743 case OCONV: 744 case OCONVIFACE: 745 case OCONVNOP: 746 case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 747 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 748 case ODOTTYPE: 749 case ODOTTYPE2: 750 case OSLICE: 751 case OSLICEARR: 752 // Conversions, field access, slice all preserve the input value. 753 escassign(e, dst, src->left); 754 break; 755 756 case OAPPEND: 757 // Append returns first argument. 758 escassign(e, dst, src->list->n); 759 break; 760 761 case OINDEX: 762 // Index of array preserves input value. 763 if(isfixedarray(src->left->type)) 764 escassign(e, dst, src->left); 765 break; 766 767 case OADD: 768 case OSUB: 769 case OOR: 770 case OXOR: 771 case OMUL: 772 case ODIV: 773 case OMOD: 774 case OLSH: 775 case ORSH: 776 case OAND: 777 case OANDNOT: 778 case OPLUS: 779 case OMINUS: 780 case OCOM: 781 // Might be pointer arithmetic, in which case 782 // the operands flow into the result. 783 // TODO(rsc): Decide what the story is here. This is unsettling. 784 escassign(e, dst, src->left); 785 escassign(e, dst, src->right); 786 break; 787 } 788 789 e->pdepth--; 790 lineno = lno; 791 } 792 793 static void 794 escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src) 795 { 796 int em; 797 798 em = parsetag(note); 799 800 if(em == EscUnknown) { 801 escassign(e, &e->theSink, src); 802 return; 803 } 804 805 for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next) 806 if(em & 1) 807 escassign(e, dsts->n, src); 808 809 if (em != 0 && dsts == nil) 810 fatal("corrupt esc tag %Z or messed up escretval list\n", note); 811 } 812 813 // This is a bit messier than fortunate, pulled out of esc's big 814 // switch for clarity. We either have the paramnodes, which may be 815 // connected to other things through flows or we have the parameter type 816 // nodes, which may be marked "noescape". Navigating the ast is slightly 817 // different for methods vs plain functions and for imported vs 818 // this-package 819 static void 820 esccall(EscState *e, Node *n) 821 { 822 NodeList *ll, *lr; 823 Node *a, *fn, *src; 824 Type *t, *fntype; 825 char buf[40]; 826 int i; 827 828 fn = N; 829 switch(n->op) { 830 default: 831 fatal("esccall"); 832 833 case OCALLFUNC: 834 fn = n->left; 835 fntype = fn->type; 836 break; 837 838 case OCALLMETH: 839 fn = n->left->right->sym->def; 840 if(fn) 841 fntype = fn->type; 842 else 843 fntype = n->left->type; 844 break; 845 846 case OCALLINTER: 847 fntype = n->left->type; 848 break; 849 } 850 851 ll = n->list; 852 if(n->list != nil && n->list->next == nil) { 853 a = n->list->n; 854 if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()). 855 ll = a->escretval; 856 } 857 858 if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) { 859 // function in same mutually recursive group. Incorporate into flow graph. 860 // print("esc local fn: %N\n", fn->ntype); 861 if(fn->defn->esc == EscFuncUnknown || n->escretval != nil) 862 fatal("graph inconsistency"); 863 864 // set up out list on this call node 865 for(lr=fn->ntype->rlist; lr; lr=lr->next) 866 n->escretval = list(n->escretval, lr->n->left); // type.rlist -> dclfield -> ONAME (PPARAMOUT) 867 868 // Receiver. 869 if(n->op != OCALLFUNC) 870 escassign(e, fn->ntype->left->left, n->left->left); 871 872 for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) { 873 src = ll->n; 874 if(lr->n->isddd && !n->isddd) { 875 // Introduce ODDDARG node to represent ... allocation. 876 src = nod(ODDDARG, N, N); 877 src->escloopdepth = e->loopdepth; 878 src->lineno = n->lineno; 879 src->esc = EscNone; // until we find otherwise 880 e->noesc = list(e->noesc, src); 881 n->right = src; 882 } 883 if(lr->n->left != N) 884 escassign(e, lr->n->left, src); 885 if(src != ll->n) 886 break; 887 } 888 // "..." arguments are untracked 889 for(; ll; ll=ll->next) 890 escassign(e, &e->theSink, ll->n); 891 892 return; 893 } 894 895 // Imported or completely analyzed function. Use the escape tags. 896 if(n->escretval != nil) 897 fatal("esc already decorated call %+N\n", n); 898 899 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 900 i = 0; 901 for(t=getoutargx(fntype)->type; t; t=t->down) { 902 src = nod(ONAME, N, N); 903 snprint(buf, sizeof buf, ".dum%d", i++); 904 src->sym = lookup(buf); 905 src->type = t->type; 906 src->class = PAUTO; 907 src->curfn = curfn; 908 src->escloopdepth = e->loopdepth; 909 src->used = 1; 910 src->lineno = n->lineno; 911 n->escretval = list(n->escretval, src); 912 } 913 914 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); 915 916 // Receiver. 917 if(n->op != OCALLFUNC) 918 escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left); 919 920 for(t=getinargx(fntype)->type; ll; ll=ll->next) { 921 src = ll->n; 922 if(t->isddd && !n->isddd) { 923 // Introduce ODDDARG node to represent ... allocation. 924 src = nod(ODDDARG, N, N); 925 src->escloopdepth = e->loopdepth; 926 src->lineno = n->lineno; 927 src->esc = EscNone; // until we find otherwise 928 e->noesc = list(e->noesc, src); 929 n->right = src; 930 } 931 escassignfromtag(e, t->note, n->escretval, src); 932 if(src != ll->n) 933 break; 934 t = t->down; 935 } 936 // "..." arguments are untracked 937 for(; ll; ll=ll->next) 938 escassign(e, &e->theSink, ll->n); 939 } 940 941 // Store the link src->dst in dst, throwing out some quick wins. 942 static void 943 escflows(EscState *e, Node *dst, Node *src) 944 { 945 if(dst == nil || src == nil || dst == src) 946 return; 947 948 // Don't bother building a graph for scalars. 949 if(src->type && !haspointers(src->type)) 950 return; 951 952 if(debug['m']>2) 953 print("%L::flows:: %hN <- %hN\n", lineno, dst, src); 954 955 if(dst->escflowsrc == nil) { 956 e->dsts = list(e->dsts, dst); 957 e->dstcount++; 958 } 959 e->edgecount++; 960 961 dst->escflowsrc = list(dst->escflowsrc, src); 962 } 963 964 // Whenever we hit a reference node, the level goes up by one, and whenever 965 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 966 // finding an OADDR just means we're following the upstream of a dereference, 967 // so this address doesn't leak (yet). 968 // If level == 0, it means the /value/ of this node can reach the root of this flood. 969 // so if this node is an OADDR, it's argument should be marked as escaping iff 970 // it's currfn/e->loopdepth are different from the flood's root. 971 // Once an object has been moved to the heap, all of it's upstream should be considered 972 // escaping to the global scope. 973 static void 974 escflood(EscState *e, Node *dst) 975 { 976 NodeList *l; 977 978 switch(dst->op) { 979 case ONAME: 980 case OCLOSURE: 981 break; 982 default: 983 return; 984 } 985 986 if(debug['m']>1) 987 print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst, 988 (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S, 989 dst->escloopdepth); 990 991 for(l = dst->escflowsrc; l; l=l->next) { 992 walkgen++; 993 escwalk(e, 0, dst, l->n); 994 } 995 } 996 997 // There appear to be some loops in the escape graph, causing 998 // arbitrary recursion into deeper and deeper levels. 999 // Cut this off safely by making minLevel sticky: once you 1000 // get that deep, you cannot go down any further but you also 1001 // cannot go up any further. This is a conservative fix. 1002 // Making minLevel smaller (more negative) would handle more 1003 // complex chains of indirections followed by address-of operations, 1004 // at the cost of repeating the traversal once for each additional 1005 // allowed level when a loop is encountered. Using -2 suffices to 1006 // pass all the tests we have written so far, which we assume matches 1007 // the level of complexity we want the escape analysis code to handle. 1008 #define MinLevel (-2) 1009 1010 static void 1011 escwalk(EscState *e, int level, Node *dst, Node *src) 1012 { 1013 NodeList *ll; 1014 int leaks, newlevel; 1015 1016 if(src->walkgen == walkgen && src->esclevel <= level) 1017 return; 1018 src->walkgen = walkgen; 1019 src->esclevel = level; 1020 1021 if(debug['m']>1) 1022 print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n", 1023 level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src, 1024 (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth); 1025 1026 e->pdepth++; 1027 1028 // Input parameter flowing to output parameter? 1029 if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) { 1030 if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) { 1031 if(src->esc != EscScope && src->esc != EscHeap) { 1032 if(debug['m']) 1033 warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym); 1034 if((src->esc&EscMask) != EscReturn) 1035 src->esc = EscReturn; 1036 src->esc |= 1<<((dst->vargen-1) + EscBits); 1037 goto recurse; 1038 } 1039 } 1040 } 1041 1042 leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth); 1043 1044 switch(src->op) { 1045 case ONAME: 1046 if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) { 1047 src->esc = EscScope; 1048 if(debug['m']) 1049 warnl(src->lineno, "leaking param: %hN", src); 1050 } 1051 1052 // Treat a PPARAMREF closure variable as equivalent to the 1053 // original variable. 1054 if(src->class == PPARAMREF) { 1055 if(leaks && debug['m']) 1056 warnl(src->lineno, "leaking closure reference %hN", src); 1057 escwalk(e, level, dst, src->closure); 1058 } 1059 break; 1060 1061 case OPTRLIT: 1062 case OADDR: 1063 if(leaks) { 1064 src->esc = EscHeap; 1065 addrescapes(src->left); 1066 if(debug['m']) 1067 warnl(src->lineno, "%hN escapes to heap", src); 1068 } 1069 newlevel = level; 1070 if(level > MinLevel) 1071 newlevel--; 1072 escwalk(e, newlevel, dst, src->left); 1073 break; 1074 1075 case OARRAYLIT: 1076 if(isfixedarray(src->type)) 1077 break; 1078 // fall through 1079 case ODDDARG: 1080 case OMAKECHAN: 1081 case OMAKEMAP: 1082 case OMAKESLICE: 1083 case OMAPLIT: 1084 case ONEW: 1085 case OCLOSURE: 1086 case OCALLPART: 1087 if(leaks) { 1088 src->esc = EscHeap; 1089 if(debug['m']) 1090 warnl(src->lineno, "%hN escapes to heap", src); 1091 } 1092 break; 1093 1094 case ODOT: 1095 escwalk(e, level, dst, src->left); 1096 break; 1097 1098 case OINDEX: 1099 if(isfixedarray(src->left->type)) { 1100 escwalk(e, level, dst, src->left); 1101 break; 1102 } 1103 // fall through 1104 case OSLICE: 1105 case ODOTPTR: 1106 case OINDEXMAP: 1107 case OIND: 1108 newlevel = level; 1109 if(level > MinLevel) 1110 newlevel++; 1111 escwalk(e, newlevel, dst, src->left); 1112 } 1113 1114 recurse: 1115 for(ll=src->escflowsrc; ll; ll=ll->next) 1116 escwalk(e, level, dst, ll->n); 1117 1118 e->pdepth--; 1119 } 1120 1121 static void 1122 esctag(EscState *e, Node *func) 1123 { 1124 Node *savefn; 1125 NodeList *ll; 1126 Type *t; 1127 1128 USED(e); 1129 func->esc = EscFuncTagged; 1130 1131 // External functions are assumed unsafe, 1132 // unless //go:noescape is given before the declaration. 1133 if(func->nbody == nil) { 1134 if(func->noescape) { 1135 for(t=getinargx(func->type)->type; t; t=t->down) 1136 if(haspointers(t->type)) 1137 t->note = mktag(EscNone); 1138 } 1139 return; 1140 } 1141 1142 savefn = curfn; 1143 curfn = func; 1144 1145 for(ll=curfn->dcl; ll; ll=ll->next) { 1146 if(ll->n->op != ONAME || ll->n->class != PPARAM) 1147 continue; 1148 1149 switch (ll->n->esc&EscMask) { 1150 case EscNone: // not touched by escflood 1151 case EscReturn: 1152 if(haspointers(ll->n->type)) // don't bother tagging for scalars 1153 ll->n->paramfld->note = mktag(ll->n->esc); 1154 break; 1155 case EscHeap: // touched by escflood, moved to heap 1156 case EscScope: // touched by escflood, value leaves scope 1157 break; 1158 } 1159 } 1160 1161 curfn = savefn; 1162 }