@@ -209,9 +209,10 @@ struct EscState {
209
209
int pdepth ; // for debug printing in recursions.
210
210
int dstcount , edgecount ; // diagnostic
211
211
NodeList * noesc ; // list of possible non-escaping nodes, for printing
212
+ int recursive ; // recursive function or group of mutually recursive functions.
212
213
};
213
214
214
- static Strlit * tags [16 ] = { nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil } ;
215
+ static Strlit * tags [16 ];
215
216
216
217
static Strlit *
217
218
mktag (int mask )
@@ -260,15 +261,14 @@ analyze(NodeList *all, int recursive)
260
261
NodeList * l ;
261
262
EscState es , * e ;
262
263
263
- USED (recursive );
264
-
265
264
memset (& es , 0 , sizeof es );
266
265
e = & es ;
267
266
e -> theSink .op = ONAME ;
268
267
e -> theSink .orig = & e -> theSink ;
269
268
e -> theSink .class = PEXTERN ;
270
269
e -> theSink .sym = lookup (".sink" );
271
270
e -> theSink .escloopdepth = -1 ;
271
+ e -> recursive = recursive ;
272
272
273
273
for (l = all ; l ; l = l -> next )
274
274
if (l -> n -> op == ODCLFUNC )
@@ -308,6 +308,8 @@ escfunc(EscState *e, Node *func)
308
308
NodeList * ll ;
309
309
int saveld ;
310
310
311
+ // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
312
+
311
313
if (func -> esc != 1 )
312
314
fatal ("repeat escfunc %N" , func -> nname );
313
315
func -> esc = EscFuncStarted ;
@@ -335,6 +337,12 @@ escfunc(EscState *e, Node *func)
335
337
}
336
338
}
337
339
340
+ // in a mutually recursive group we lose track of the return values
341
+ if (e -> recursive )
342
+ for (ll = curfn -> dcl ; ll ; ll = ll -> next )
343
+ if (ll -> n -> op == ONAME && ll -> n -> class == PPARAMOUT )
344
+ escflows (e , & e -> theSink , ll -> n );
345
+
338
346
escloopdepthlist (e , curfn -> nbody );
339
347
esclist (e , curfn -> nbody );
340
348
curfn = savefn ;
@@ -450,7 +458,7 @@ esc(EscState *e, Node *n)
450
458
}
451
459
// See case OLABEL in escloopdepth above
452
460
// else if(n->left->sym->label == nil)
453
- // fatal("escape anaylysis missed or messed up a label: %+N", n);
461
+ // fatal("escape analysis missed or messed up a label: %+N", n);
454
462
455
463
n -> left -> sym -> label = nil ;
456
464
break ;
@@ -506,13 +514,30 @@ esc(EscState *e, Node *n)
506
514
escassign (e , & e -> theSink , ll -> n );
507
515
break ;
508
516
517
+ case OCALLMETH :
518
+ case OCALLFUNC :
519
+ case OCALLINTER :
520
+ esccall (e , n );
521
+ break ;
522
+
523
+ case OAS2FUNC : // x,y = f()
524
+ // esccall already done on n->rlist->n. tie it's escretval to n->list
525
+ lr = n -> rlist -> n -> escretval ;
526
+ for (ll = n -> list ; lr && ll ; lr = lr -> next , ll = ll -> next )
527
+ escassign (e , ll -> n , lr -> n );
528
+ if (lr || ll )
529
+ fatal ("esc oas2func" );
530
+ break ;
531
+
509
532
case ORETURN :
533
+ ll = n -> list ;
510
534
if (count (n -> list ) == 1 && curfn -> type -> outtuple > 1 ) {
511
535
// OAS2FUNC in disguise
512
- break ;
536
+ // esccall already done on n->list->n
537
+ // tie n->list->n->escretval to curfn->dcl PPARAMOUT's
538
+ ll = n -> list -> n -> escretval ;
513
539
}
514
540
515
- ll = n -> list ;
516
541
for (lr = curfn -> dcl ; lr && ll ; lr = lr -> next ) {
517
542
if (lr -> n -> op != ONAME || lr -> n -> class != PPARAMOUT )
518
543
continue ;
@@ -534,12 +559,6 @@ esc(EscState *e, Node *n)
534
559
escassign (e , & e -> theSink , ll -> n ); // lose track of assign to dereference
535
560
break ;
536
561
537
- case OCALLMETH :
538
- case OCALLFUNC :
539
- case OCALLINTER :
540
- esccall (e , n );
541
- break ;
542
-
543
562
case OCONV :
544
563
case OCONVNOP :
545
564
case OCONVIFACE :
@@ -693,6 +712,14 @@ escassign(EscState *e, Node *dst, Node *src)
693
712
escflows (e , dst , src );
694
713
break ;
695
714
715
+ case OCALLMETH :
716
+ case OCALLFUNC :
717
+ case OCALLINTER :
718
+ if (count (src -> escretval ) != 1 )
719
+ fatal ("escassign from call %+N" , src );
720
+ escflows (e , dst , src -> escretval -> n );
721
+ break ;
722
+
696
723
case ODOT :
697
724
// A non-pointer escaping from a struct does not concern us.
698
725
if (src -> type && !haspointers (src -> type ))
@@ -748,6 +775,26 @@ escassign(EscState *e, Node *dst, Node *src)
748
775
lineno = lno ;
749
776
}
750
777
778
+ static void
779
+ escassignfromtag (EscState * e , Strlit * note , NodeList * dsts , Node * src )
780
+ {
781
+ int em ;
782
+
783
+ em = parsetag (note );
784
+
785
+ if (em == EscUnknown ) {
786
+ escassign (e , & e -> theSink , src );
787
+ return ;
788
+ }
789
+
790
+ for (em >>= EscBits ; em && dsts ; em >>= 1 , dsts = dsts -> next )
791
+ if (em & 1 )
792
+ escassign (e , dsts -> n , src );
793
+
794
+ if (em != 0 && dsts == nil )
795
+ fatal ("corrupt esc tag %Z or messed up escretval list\n" , note );
796
+ }
797
+
751
798
// This is a bit messier than fortunate, pulled out of esc's big
752
799
// switch for clarity. We either have the paramnodes, which may be
753
800
// connected to other things throug flows or we have the parameter type
@@ -760,6 +807,8 @@ esccall(EscState *e, Node *n)
760
807
NodeList * ll , * lr ;
761
808
Node * a , * fn , * src ;
762
809
Type * t , * fntype ;
810
+ char buf [40 ];
811
+ int i ;
763
812
764
813
fn = N ;
765
814
switch (n -> op ) {
@@ -787,19 +836,20 @@ esccall(EscState *e, Node *n)
787
836
ll = n -> list ;
788
837
if (n -> list != nil && n -> list -> next == nil ) {
789
838
a = n -> list -> n ;
790
- if (a -> type -> etype == TSTRUCT && a -> type -> funarg ) {
791
- // f(g()).
792
- // Since f's arguments are g's results and
793
- // all function results escape, we're done.
794
- ll = nil ;
795
- }
839
+ if (a -> type -> etype == TSTRUCT && a -> type -> funarg ) // f(g()).
840
+ ll = a -> escretval ;
796
841
}
797
842
798
843
if (fn && fn -> op == ONAME && fn -> class == PFUNC && fn -> defn && fn -> defn -> nbody && fn -> ntype && fn -> defn -> esc < EscFuncTagged ) {
799
- // Local function in this round. Incorporate into flow graph.
800
- if (fn -> defn -> esc == EscFuncUnknown )
844
+ // function in same mutually recursive group. Incorporate into flow graph.
845
+ // print("esc local fn: %N\n", fn->ntype);
846
+ if (fn -> defn -> esc == EscFuncUnknown || n -> escretval != nil )
801
847
fatal ("graph inconsistency" );
802
848
849
+ // set up out list on this call node
850
+ for (lr = fn -> ntype -> rlist ; lr ; lr = lr -> next )
851
+ n -> escretval = list (n -> escretval , lr -> n -> left ); // type.rlist -> dclfield -> ONAME (PPARAMOUT)
852
+
803
853
// Receiver.
804
854
if (n -> op != OCALLFUNC )
805
855
escassign (e , fn -> ntype -> left -> left , n -> left -> left );
@@ -823,15 +873,35 @@ esccall(EscState *e, Node *n)
823
873
// "..." arguments are untracked
824
874
for (; ll ; ll = ll -> next )
825
875
escassign (e , & e -> theSink , ll -> n );
876
+
826
877
return ;
827
878
}
828
879
829
880
// Imported or completely analyzed function. Use the escape tags.
830
- if (n -> op != OCALLFUNC ) {
831
- t = getthisx (fntype )-> type ;
832
- if (parsetag (t -> note ) != EscNone )
833
- escassign (e , & e -> theSink , n -> left -> left );
881
+ if (n -> escretval != nil )
882
+ fatal ("esc already decorated call %+N\n" , n );
883
+
884
+ // set up out list on this call node with dummy auto ONAMES in the current (calling) function.
885
+ i = 0 ;
886
+ for (t = getoutargx (fntype )-> type ; t ; t = t -> down ) {
887
+ src = nod (ONAME , N , N );
888
+ snprint (buf , sizeof buf , ".dum%d" , i ++ );
889
+ src -> sym = lookup (buf );
890
+ src -> type = t -> type ;
891
+ src -> class = PAUTO ;
892
+ src -> curfn = curfn ;
893
+ src -> escloopdepth = e -> loopdepth ;
894
+ src -> used = 1 ;
895
+ src -> lineno = n -> lineno ;
896
+ n -> escretval = list (n -> escretval , src );
834
897
}
898
+
899
+ // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
900
+
901
+ // Receiver.
902
+ if (n -> op != OCALLFUNC )
903
+ escassignfromtag (e , getthisx (fntype )-> type -> note , n -> escretval , n -> left -> left );
904
+
835
905
for (t = getinargx (fntype )-> type ; ll ; ll = ll -> next ) {
836
906
src = ll -> n ;
837
907
if (t -> isddd && !n -> isddd ) {
@@ -843,8 +913,7 @@ esccall(EscState *e, Node *n)
843
913
e -> noesc = list (e -> noesc , src );
844
914
n -> right = src ;
845
915
}
846
- if (parsetag (t -> note ) != EscNone )
847
- escassign (e , & e -> theSink , src );
916
+ escassignfromtag (e , t -> note , n -> escretval , src );
848
917
if (src != ll -> n )
849
918
break ;
850
919
t = t -> down ;
0 commit comments