github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/gsubr.go (about) 1 // Derived from Inferno utils/6c/txt.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/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 gc 32 33 import ( 34 "github.com/gagliardetto/golang-go/cmd/compile/internal/ssa" 35 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 36 "github.com/gagliardetto/golang-go/cmd/internal/obj" 37 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 38 "github.com/gagliardetto/golang-go/cmd/internal/src" 39 ) 40 41 var sharedProgArray = new([10000]obj.Prog) // *T instead of T to work around issue 19839 42 43 // Progs accumulates Progs for a function and converts them into machine code. 44 type Progs struct { 45 Text *obj.Prog // ATEXT Prog for this function 46 next *obj.Prog // next Prog 47 pc int64 // virtual PC; count of Progs 48 pos src.XPos // position to use for new Progs 49 curfn *Node // fn these Progs are for 50 progcache []obj.Prog // local progcache 51 cacheidx int // first free element of progcache 52 53 nextLive LivenessIndex // liveness index for the next Prog 54 prevLive LivenessIndex // last emitted liveness index 55 } 56 57 // newProgs returns a new Progs for fn. 58 // worker indicates which of the backend workers will use the Progs. 59 func newProgs(fn *Node, worker int) *Progs { 60 pp := new(Progs) 61 if Ctxt.CanReuseProgs() { 62 sz := len(sharedProgArray) / nBackendWorkers 63 pp.progcache = sharedProgArray[sz*worker : sz*(worker+1)] 64 } 65 pp.curfn = fn 66 67 // prime the pump 68 pp.next = pp.NewProg() 69 pp.clearp(pp.next) 70 71 pp.pos = fn.Pos 72 pp.settext(fn) 73 pp.nextLive = LivenessInvalid 74 // PCDATA tables implicitly start with index -1. 75 pp.prevLive = LivenessIndex{-1, -1} 76 return pp 77 } 78 79 func (pp *Progs) NewProg() *obj.Prog { 80 var p *obj.Prog 81 if pp.cacheidx < len(pp.progcache) { 82 p = &pp.progcache[pp.cacheidx] 83 pp.cacheidx++ 84 } else { 85 p = new(obj.Prog) 86 } 87 p.Ctxt = Ctxt 88 return p 89 } 90 91 // Flush converts from pp to machine code. 92 func (pp *Progs) Flush() { 93 plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.curfn} 94 obj.Flushplist(Ctxt, plist, pp.NewProg, myimportpath) 95 } 96 97 // Free clears pp and any associated resources. 98 func (pp *Progs) Free() { 99 if Ctxt.CanReuseProgs() { 100 // Clear progs to enable GC and avoid abuse. 101 s := pp.progcache[:pp.cacheidx] 102 for i := range s { 103 s[i] = obj.Prog{} 104 } 105 } 106 // Clear pp to avoid abuse. 107 *pp = Progs{} 108 } 109 110 // Prog adds a Prog with instruction As to pp. 111 func (pp *Progs) Prog(as obj.As) *obj.Prog { 112 if pp.nextLive.stackMapIndex != pp.prevLive.stackMapIndex { 113 // Emit stack map index change. 114 idx := pp.nextLive.stackMapIndex 115 pp.prevLive.stackMapIndex = idx 116 p := pp.Prog(obj.APCDATA) 117 Addrconst(&p.From, objabi.PCDATA_StackMapIndex) 118 Addrconst(&p.To, int64(idx)) 119 } 120 if pp.nextLive.regMapIndex != pp.prevLive.regMapIndex { 121 // Emit register map index change. 122 idx := pp.nextLive.regMapIndex 123 pp.prevLive.regMapIndex = idx 124 p := pp.Prog(obj.APCDATA) 125 Addrconst(&p.From, objabi.PCDATA_RegMapIndex) 126 Addrconst(&p.To, int64(idx)) 127 } 128 129 p := pp.next 130 pp.next = pp.NewProg() 131 pp.clearp(pp.next) 132 p.Link = pp.next 133 134 if !pp.pos.IsKnown() && Debug['K'] != 0 { 135 Warn("prog: unknown position (line 0)") 136 } 137 138 p.As = as 139 p.Pos = pp.pos 140 if pp.pos.IsStmt() == src.PosIsStmt { 141 // Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt 142 if ssa.LosesStmtMark(as) { 143 return p 144 } 145 pp.pos = pp.pos.WithNotStmt() 146 } 147 return p 148 } 149 150 func (pp *Progs) clearp(p *obj.Prog) { 151 obj.Nopout(p) 152 p.As = obj.AEND 153 p.Pc = pp.pc 154 pp.pc++ 155 } 156 157 func (pp *Progs) Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog { 158 q := pp.NewProg() 159 pp.clearp(q) 160 q.As = as 161 q.Pos = p.Pos 162 q.From.Type = ftype 163 q.From.Reg = freg 164 q.From.Offset = foffset 165 q.To.Type = ttype 166 q.To.Reg = treg 167 q.To.Offset = toffset 168 q.Link = p.Link 169 p.Link = q 170 return q 171 } 172 173 func (pp *Progs) settext(fn *Node) { 174 if pp.Text != nil { 175 Fatalf("Progs.settext called twice") 176 } 177 ptxt := pp.Prog(obj.ATEXT) 178 pp.Text = ptxt 179 180 fn.Func.lsym.Func.Text = ptxt 181 ptxt.From.Type = obj.TYPE_MEM 182 ptxt.From.Name = obj.NAME_EXTERN 183 ptxt.From.Sym = fn.Func.lsym 184 } 185 186 // initLSym defines f's obj.LSym and initializes it based on the 187 // properties of f. This includes setting the symbol flags and ABI and 188 // creating and initializing related DWARF symbols. 189 // 190 // initLSym must be called exactly once per function and must be 191 // called for both functions with bodies and functions without bodies. 192 func (f *Func) initLSym(hasBody bool) { 193 if f.lsym != nil { 194 Fatalf("Func.initLSym called twice") 195 } 196 197 if nam := f.Nname; !nam.isBlank() { 198 f.lsym = nam.Sym.Linksym() 199 if f.Pragma&Systemstack != 0 { 200 f.lsym.Set(obj.AttrCFunc, true) 201 } 202 203 var aliasABI obj.ABI 204 needABIAlias := false 205 defABI, hasDefABI := symabiDefs[f.lsym.Name] 206 if hasDefABI && defABI == obj.ABI0 { 207 // Symbol is defined as ABI0. Create an 208 // Internal -> ABI0 wrapper. 209 f.lsym.SetABI(obj.ABI0) 210 needABIAlias, aliasABI = true, obj.ABIInternal 211 } else { 212 // No ABI override. Check that the symbol is 213 // using the expected ABI. 214 want := obj.ABIInternal 215 if f.lsym.ABI() != want { 216 Fatalf("function symbol %s has the wrong ABI %v, expected %v", f.lsym.Name, f.lsym.ABI(), want) 217 } 218 } 219 220 isLinknameExported := nam.Sym.Linkname != "" && (hasBody || hasDefABI) 221 if abi, ok := symabiRefs[f.lsym.Name]; (ok && abi == obj.ABI0) || isLinknameExported { 222 // Either 1) this symbol is definitely 223 // referenced as ABI0 from this package; or 2) 224 // this symbol is defined in this package but 225 // given a linkname, indicating that it may be 226 // referenced from another package. Create an 227 // ABI0 -> Internal wrapper so it can be 228 // called as ABI0. In case 2, it's important 229 // that we know it's defined in this package 230 // since other packages may "pull" symbols 231 // using linkname and we don't want to create 232 // duplicate ABI wrappers. 233 if f.lsym.ABI() != obj.ABI0 { 234 needABIAlias, aliasABI = true, obj.ABI0 235 } 236 } 237 238 if needABIAlias { 239 // These LSyms have the same name as the 240 // native function, so we create them directly 241 // rather than looking them up. The uniqueness 242 // of f.lsym ensures uniqueness of asym. 243 asym := &obj.LSym{ 244 Name: f.lsym.Name, 245 Type: objabi.SABIALIAS, 246 R: []obj.Reloc{{Sym: f.lsym}}, // 0 size, so "informational" 247 } 248 asym.SetABI(aliasABI) 249 asym.Set(obj.AttrDuplicateOK, true) 250 Ctxt.ABIAliases = append(Ctxt.ABIAliases, asym) 251 } 252 } 253 254 if !hasBody { 255 // For body-less functions, we only create the LSym. 256 return 257 } 258 259 var flag int 260 if f.Dupok() { 261 flag |= obj.DUPOK 262 } 263 if f.Wrapper() { 264 flag |= obj.WRAPPER 265 } 266 if f.Needctxt() { 267 flag |= obj.NEEDCTXT 268 } 269 if f.Pragma&Nosplit != 0 { 270 flag |= obj.NOSPLIT 271 } 272 if f.ReflectMethod() { 273 flag |= obj.REFLECTMETHOD 274 } 275 276 // Clumsy but important. 277 // See test/recover.go for test cases and src/reflect/value.go 278 // for the actual functions being considered. 279 if myimportpath == "reflect" { 280 switch f.Nname.Sym.Name { 281 case "callReflect", "callMethod": 282 flag |= obj.WRAPPER 283 } 284 } 285 286 Ctxt.InitTextSym(f.lsym, flag) 287 } 288 289 func ggloblnod(nam *Node) { 290 s := nam.Sym.Linksym() 291 s.Gotype = ngotype(nam).Linksym() 292 flags := 0 293 if nam.Name.Readonly() { 294 flags = obj.RODATA 295 } 296 if nam.Type != nil && !types.Haspointers(nam.Type) { 297 flags |= obj.NOPTR 298 } 299 Ctxt.Globl(s, nam.Type.Width, flags) 300 if nam.Name.LibfuzzerExtraCounter() { 301 s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER 302 } 303 } 304 305 func ggloblsym(s *obj.LSym, width int32, flags int16) { 306 if flags&obj.LOCAL != 0 { 307 s.Set(obj.AttrLocal, true) 308 flags &^= obj.LOCAL 309 } 310 Ctxt.Globl(s, int64(width), int(flags)) 311 } 312 313 func Addrconst(a *obj.Addr, v int64) { 314 a.Sym = nil 315 a.Type = obj.TYPE_CONST 316 a.Offset = v 317 } 318 319 func Patch(p *obj.Prog, to *obj.Prog) { 320 if p.To.Type != obj.TYPE_BRANCH { 321 Fatalf("patch: not a branch") 322 } 323 p.To.Val = to 324 p.To.Offset = to.Pc 325 }