github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/objw/prog.go (about) 1 // Derived from Inferno utils/6c/txt.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/txt.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package objw 32 33 import ( 34 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 35 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 36 "github.com/bir3/gocompiler/src/cmd/internal/obj" 37 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 38 "github.com/bir3/gocompiler/src/cmd/internal/src" 39 ) 40 41 var sharedProgArray = new([10000]obj.Prog) // *T instead of T to work around issue 19839 42 43 // NewProgs returns a new Progs for fn. 44 // worker indicates which of the backend workers will use the Progs. 45 func NewProgs(fn *ir.Func, worker int) *Progs { 46 pp := new(Progs) 47 if base.Ctxt.CanReuseProgs() { 48 sz := len(sharedProgArray) / base.Flag.LowerC 49 pp.Cache = sharedProgArray[sz*worker : sz*(worker+1)] 50 } 51 pp.CurFunc = fn 52 53 // prime the pump 54 pp.Next = pp.NewProg() 55 pp.Clear(pp.Next) 56 57 pp.Pos = fn.Pos() 58 pp.SetText(fn) 59 // PCDATA tables implicitly start with index -1. 60 pp.PrevLive = LivenessIndex{-1, false} 61 pp.NextLive = pp.PrevLive 62 return pp 63 } 64 65 // Progs accumulates Progs for a function and converts them into machine code. 66 type Progs struct { 67 Text *obj.Prog // ATEXT Prog for this function 68 Next *obj.Prog // next Prog 69 PC int64 // virtual PC; count of Progs 70 Pos src.XPos // position to use for new Progs 71 CurFunc *ir.Func // fn these Progs are for 72 Cache []obj.Prog // local progcache 73 CacheIndex int // first free element of progcache 74 75 NextLive LivenessIndex // liveness index for the next Prog 76 PrevLive LivenessIndex // last emitted liveness index 77 } 78 79 // LivenessIndex stores the liveness map information for a Value. 80 type LivenessIndex struct { 81 StackMapIndex int 82 83 // IsUnsafePoint indicates that this is an unsafe-point. 84 // 85 // Note that it's possible for a call Value to have a stack 86 // map while also being an unsafe-point. This means it cannot 87 // be preempted at this instruction, but that a preemption or 88 // stack growth may happen in the called function. 89 IsUnsafePoint bool 90 } 91 92 // StackMapDontCare indicates that the stack map index at a Value 93 // doesn't matter. 94 // 95 // This is a sentinel value that should never be emitted to the PCDATA 96 // stream. We use -1000 because that's obviously never a valid stack 97 // index (but -1 is). 98 const StackMapDontCare = -1000 99 100 // LivenessDontCare indicates that the liveness information doesn't 101 // matter. Currently it is used in deferreturn liveness when we don't 102 // actually need it. It should never be emitted to the PCDATA stream. 103 var LivenessDontCare = LivenessIndex{StackMapDontCare, true} 104 105 func (idx LivenessIndex) StackMapValid() bool { 106 return idx.StackMapIndex != StackMapDontCare 107 } 108 109 func (pp *Progs) NewProg() *obj.Prog { 110 var p *obj.Prog 111 if pp.CacheIndex < len(pp.Cache) { 112 p = &pp.Cache[pp.CacheIndex] 113 pp.CacheIndex++ 114 } else { 115 p = new(obj.Prog) 116 } 117 p.Ctxt = base.Ctxt 118 return p 119 } 120 121 // Flush converts from pp to machine code. 122 func (pp *Progs) Flush() { 123 plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.CurFunc} 124 obj.Flushplist(base.Ctxt, plist, pp.NewProg, base.Ctxt.Pkgpath) 125 } 126 127 // Free clears pp and any associated resources. 128 func (pp *Progs) Free() { 129 if base.Ctxt.CanReuseProgs() { 130 // Clear progs to enable GC and avoid abuse. 131 s := pp.Cache[:pp.CacheIndex] 132 for i := range s { 133 s[i] = obj.Prog{} 134 } 135 } 136 // Clear pp to avoid abuse. 137 *pp = Progs{} 138 } 139 140 // Prog adds a Prog with instruction As to pp. 141 func (pp *Progs) Prog(as obj.As) *obj.Prog { 142 if pp.NextLive.StackMapValid() && pp.NextLive.StackMapIndex != pp.PrevLive.StackMapIndex { 143 // Emit stack map index change. 144 idx := pp.NextLive.StackMapIndex 145 pp.PrevLive.StackMapIndex = idx 146 p := pp.Prog(obj.APCDATA) 147 p.From.SetConst(objabi.PCDATA_StackMapIndex) 148 p.To.SetConst(int64(idx)) 149 } 150 if pp.NextLive.IsUnsafePoint != pp.PrevLive.IsUnsafePoint { 151 // Emit unsafe-point marker. 152 pp.PrevLive.IsUnsafePoint = pp.NextLive.IsUnsafePoint 153 p := pp.Prog(obj.APCDATA) 154 p.From.SetConst(objabi.PCDATA_UnsafePoint) 155 if pp.NextLive.IsUnsafePoint { 156 p.To.SetConst(objabi.PCDATA_UnsafePointUnsafe) 157 } else { 158 p.To.SetConst(objabi.PCDATA_UnsafePointSafe) 159 } 160 } 161 162 p := pp.Next 163 pp.Next = pp.NewProg() 164 pp.Clear(pp.Next) 165 p.Link = pp.Next 166 167 if !pp.Pos.IsKnown() && base.Flag.K != 0 { 168 base.Warn("prog: unknown position (line 0)") 169 } 170 171 p.As = as 172 p.Pos = pp.Pos 173 if pp.Pos.IsStmt() == src.PosIsStmt { 174 // Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt 175 if LosesStmtMark(as) { 176 return p 177 } 178 pp.Pos = pp.Pos.WithNotStmt() 179 } 180 return p 181 } 182 183 func (pp *Progs) Clear(p *obj.Prog) { 184 obj.Nopout(p) 185 p.As = obj.AEND 186 p.Pc = pp.PC 187 pp.PC++ 188 } 189 190 func (pp *Progs) Append(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog { 191 q := pp.NewProg() 192 pp.Clear(q) 193 q.As = as 194 q.Pos = p.Pos 195 q.From.Type = ftype 196 q.From.Reg = freg 197 q.From.Offset = foffset 198 q.To.Type = ttype 199 q.To.Reg = treg 200 q.To.Offset = toffset 201 q.Link = p.Link 202 p.Link = q 203 return q 204 } 205 206 func (pp *Progs) SetText(fn *ir.Func) { 207 if pp.Text != nil { 208 base.Fatalf("Progs.SetText called twice") 209 } 210 ptxt := pp.Prog(obj.ATEXT) 211 pp.Text = ptxt 212 213 fn.LSym.Func().Text = ptxt 214 ptxt.From.Type = obj.TYPE_MEM 215 ptxt.From.Name = obj.NAME_EXTERN 216 ptxt.From.Sym = fn.LSym 217 } 218 219 // LosesStmtMark reports whether a prog with op as loses its statement mark on the way to DWARF. 220 // The attributes from some opcodes are lost in translation. 221 // TODO: this is an artifact of how funcpctab combines information for instructions at a single PC. 222 // Should try to fix it there. 223 func LosesStmtMark(as obj.As) bool { 224 // is_stmt does not work for these; it DOES for ANOP even though that generates no code. 225 return as == obj.APCDATA || as == obj.AFUNCDATA 226 }