github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/escape/assign.go (about) 1 // Copyright 2018 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 package escape 6 7 import ( 8 "github.com/go-asm/go/cmd/compile/base" 9 "github.com/go-asm/go/cmd/compile/ir" 10 ) 11 12 // addr evaluates an addressable expression n and returns a hole 13 // that represents storing into the represented location. 14 func (e *escape) addr(n ir.Node) hole { 15 if n == nil || ir.IsBlank(n) { 16 // Can happen in select case, range, maybe others. 17 return e.discardHole() 18 } 19 20 k := e.heapHole() 21 22 switch n.Op() { 23 default: 24 base.Fatalf("unexpected addr: %v", n) 25 case ir.ONAME: 26 n := n.(*ir.Name) 27 if n.Class == ir.PEXTERN { 28 break 29 } 30 k = e.oldLoc(n).asHole() 31 case ir.OLINKSYMOFFSET: 32 break 33 case ir.ODOT: 34 n := n.(*ir.SelectorExpr) 35 k = e.addr(n.X) 36 case ir.OINDEX: 37 n := n.(*ir.IndexExpr) 38 e.discard(n.Index) 39 if n.X.Type().IsArray() { 40 k = e.addr(n.X) 41 } else { 42 e.mutate(n.X) 43 } 44 case ir.ODEREF: 45 n := n.(*ir.StarExpr) 46 e.mutate(n.X) 47 case ir.ODOTPTR: 48 n := n.(*ir.SelectorExpr) 49 e.mutate(n.X) 50 case ir.OINDEXMAP: 51 n := n.(*ir.IndexExpr) 52 e.discard(n.X) 53 e.assignHeap(n.Index, "key of map put", n) 54 } 55 56 return k 57 } 58 59 func (e *escape) mutate(n ir.Node) { 60 e.expr(e.mutatorHole(), n) 61 } 62 63 func (e *escape) addrs(l ir.Nodes) []hole { 64 var ks []hole 65 for _, n := range l { 66 ks = append(ks, e.addr(n)) 67 } 68 return ks 69 } 70 71 func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) { 72 e.expr(e.heapHole().note(where, why), src) 73 } 74 75 // assignList evaluates the assignment dsts... = srcs.... 76 func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) { 77 ks := e.addrs(dsts) 78 for i, k := range ks { 79 var src ir.Node 80 if i < len(srcs) { 81 src = srcs[i] 82 } 83 84 if dst := dsts[i]; dst != nil { 85 // Detect implicit conversion of uintptr to unsafe.Pointer when 86 // storing into reflect.{Slice,String}Header. 87 if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) { 88 e.unsafeValue(e.heapHole().note(where, why), src) 89 continue 90 } 91 92 // Filter out some no-op assignments for escape analysis. 93 if src != nil && isSelfAssign(dst, src) { 94 if base.Flag.LowerM != 0 { 95 base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where) 96 } 97 k = e.discardHole() 98 } 99 } 100 101 e.expr(k.note(where, why), src) 102 } 103 104 e.reassigned(ks, where) 105 } 106 107 // reassigned marks the locations associated with the given holes as 108 // reassigned, unless the location represents a variable declared and 109 // assigned exactly once by where. 110 func (e *escape) reassigned(ks []hole, where ir.Node) { 111 if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil { 112 if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil { 113 // Zero-value assignment for variable declared without an 114 // explicit initial value. Assume this is its initialization 115 // statement. 116 return 117 } 118 } 119 120 for _, k := range ks { 121 loc := k.dst 122 // Variables declared by range statements are assigned on every iteration. 123 if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE { 124 continue 125 } 126 loc.reassigned = true 127 } 128 }