@@ -122,17 +122,24 @@ type escape struct {
122
122
}
123
123
124
124
func Funcs (all []* ir.Func ) {
125
- ir .VisitFuncsBottomUp (all , Batch )
125
+ // Make a cache of ir.ReassignOracles. The cache is lazily populated.
126
+ // TODO(thepudds): consider adding a field on ir.Func instead. We might also be able
127
+ // to use that field elsewhere, like in walk. See discussion in https://go.dev/cl/688075.
128
+ reassignOracles := make (map [* ir.Func ]* ir.ReassignOracle )
129
+
130
+ ir .VisitFuncsBottomUp (all , func (list []* ir.Func , recursive bool ) {
131
+ Batch (list , reassignOracles )
132
+ })
126
133
}
127
134
128
135
// Batch performs escape analysis on a minimal batch of
129
136
// functions.
130
- func Batch (fns []* ir.Func , recursive bool ) {
137
+ func Batch (fns []* ir.Func , reassignOracles map [ * ir. Func ] * ir. ReassignOracle ) {
131
138
var b batch
132
139
b .heapLoc .attrs = attrEscapes | attrPersists | attrMutates | attrCalls
133
140
b .mutatorLoc .attrs = attrMutates
134
141
b .calleeLoc .attrs = attrCalls
135
- b .reassignOracles = make ( map [ * ir. Func ] * ir. ReassignOracle )
142
+ b .reassignOracles = reassignOracles
136
143
137
144
// Construct data-flow graph from syntax trees.
138
145
for _ , fn := range fns {
@@ -531,19 +538,9 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
531
538
if n == nil || fn == nil {
532
539
return
533
540
}
534
- if n .Op () != ir .OMAKESLICE && n .Op () != ir .OCONVIFACE {
535
- return
536
- }
537
541
538
- // Look up a cached ReassignOracle for the function, lazily computing one if needed.
539
- ro := b .reassignOracle (fn )
540
- if ro == nil {
541
- base .Fatalf ("no ReassignOracle for function %v with closure parent %v" , fn , fn .ClosureParent )
542
- }
543
-
544
- assignTemp := func (n ir.Node , init * ir.Nodes ) {
542
+ assignTemp := func (pos src.XPos , n ir.Node , init * ir.Nodes ) {
545
543
// Preserve any side effects of n by assigning it to an otherwise unused temp.
546
- pos := n .Pos ()
547
544
tmp := typecheck .TempAt (pos , fn , n .Type ())
548
545
init .Append (typecheck .Stmt (ir .NewDecl (pos , ir .ODCL , tmp )))
549
546
init .Append (typecheck .Stmt (ir .NewAssignStmt (pos , tmp , n )))
@@ -561,6 +558,11 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
561
558
}
562
559
563
560
if (* r ).Op () != ir .OLITERAL {
561
+ // Look up a cached ReassignOracle for the function, lazily computing one if needed.
562
+ ro := b .reassignOracle (fn )
563
+ if ro == nil {
564
+ base .Fatalf ("no ReassignOracle for function %v with closure parent %v" , fn , fn .ClosureParent )
565
+ }
564
566
if s := ro .StaticValue (* r ); s .Op () == ir .OLITERAL {
565
567
lit , ok := s .(* ir.BasicLit )
566
568
if ! ok || lit .Val ().Kind () != constant .Int {
@@ -572,8 +574,8 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
572
574
return
573
575
}
574
576
// Preserve any side effects of the original expression, then replace it.
575
- assignTemp (* r , n .PtrInit ())
576
- * r = lit
577
+ assignTemp (n . Pos (), * r , n .PtrInit ())
578
+ * r = ir . NewBasicLit ( n . Pos (), ( * r ). Type (), lit . Val ())
577
579
}
578
580
}
579
581
}
@@ -582,6 +584,12 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
582
584
// a literal to avoid heap allocating the underlying interface value.
583
585
conv := n .(* ir.ConvExpr )
584
586
if conv .X .Op () != ir .OLITERAL && ! conv .X .Type ().IsInterface () {
587
+ // TODO(thepudds): likely could avoid some work by tightening the check of conv.X's type.
588
+ // Look up a cached ReassignOracle for the function, lazily computing one if needed.
589
+ ro := b .reassignOracle (fn )
590
+ if ro == nil {
591
+ base .Fatalf ("no ReassignOracle for function %v with closure parent %v" , fn , fn .ClosureParent )
592
+ }
585
593
v := ro .StaticValue (conv .X )
586
594
if v != nil && v .Op () == ir .OLITERAL && ir .ValidTypeForConst (conv .X .Type (), v .Val ()) {
587
595
if ! base .LiteralAllocHash .MatchPos (n .Pos (), nil ) {
@@ -592,9 +600,9 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
592
600
base .WarnfAt (n .Pos (), "rewriting OCONVIFACE value from %v (%v) to %v (%v)" , conv .X , conv .X .Type (), v , v .Type ())
593
601
}
594
602
// Preserve any side effects of the original expression, then replace it.
595
- assignTemp (conv .X , conv .PtrInit ())
603
+ assignTemp (conv .Pos (), conv . X , conv .PtrInit ())
596
604
v := v .(* ir.BasicLit )
597
- conv .X = ir .NewBasicLit (conv .X . Pos (), conv .X .Type (), v .Val ())
605
+ conv .X = ir .NewBasicLit (conv .Pos (), conv .X .Type (), v .Val ())
598
606
typecheck .Expr (conv )
599
607
}
600
608
}
0 commit comments