github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/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 "cmd/compile/internal/types" 35 "cmd/internal/obj" 36 "cmd/internal/objabi" 37 "cmd/internal/src" 38 ) 39 40 var sharedProgArray = new([10000]obj.Prog) // *T instead of T to work around issue 19839 41 42 // Progs accumulates Progs for a function and converts them into machine code. 43 type Progs struct { 44 Text *obj.Prog // ATEXT Prog for this function 45 next *obj.Prog // next Prog 46 pc int64 // virtual PC; count of Progs 47 pos src.XPos // position to use for new Progs 48 curfn *Node // fn these Progs are for 49 progcache []obj.Prog // local progcache 50 cacheidx int // first free element of progcache 51 } 52 53 // newProgs returns a new Progs for fn. 54 // worker indicates which of the backend workers will use the Progs. 55 func newProgs(fn *Node, worker int) *Progs { 56 pp := new(Progs) 57 if Ctxt.CanReuseProgs() { 58 sz := len(sharedProgArray) / nBackendWorkers 59 pp.progcache = sharedProgArray[sz*worker : sz*(worker+1)] 60 } 61 pp.curfn = fn 62 63 // prime the pump 64 pp.next = pp.NewProg() 65 pp.clearp(pp.next) 66 67 pp.pos = fn.Pos 68 pp.settext(fn) 69 return pp 70 } 71 72 func (pp *Progs) NewProg() *obj.Prog { 73 var p *obj.Prog 74 if pp.cacheidx < len(pp.progcache) { 75 p = &pp.progcache[pp.cacheidx] 76 pp.cacheidx++ 77 } else { 78 p = new(obj.Prog) 79 } 80 p.Ctxt = Ctxt 81 return p 82 } 83 84 // Flush converts from pp to machine code. 85 func (pp *Progs) Flush() { 86 plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.curfn} 87 obj.Flushplist(Ctxt, plist, pp.NewProg) 88 } 89 90 // Free clears pp and any associated resources. 91 func (pp *Progs) Free() { 92 if Ctxt.CanReuseProgs() { 93 // Clear progs to enable GC and avoid abuse. 94 s := pp.progcache[:pp.cacheidx] 95 for i := range s { 96 s[i] = obj.Prog{} 97 } 98 } 99 // Clear pp to avoid abuse. 100 *pp = Progs{} 101 } 102 103 // Prog adds a Prog with instruction As to pp. 104 func (pp *Progs) Prog(as obj.As) *obj.Prog { 105 p := pp.next 106 pp.next = pp.NewProg() 107 pp.clearp(pp.next) 108 p.Link = pp.next 109 110 if !pp.pos.IsKnown() && Debug['K'] != 0 { 111 Warn("prog: unknown position (line 0)") 112 } 113 114 p.As = as 115 p.Pos = pp.pos 116 return p 117 } 118 119 func (pp *Progs) clearp(p *obj.Prog) { 120 obj.Nopout(p) 121 p.As = obj.AEND 122 p.Pc = pp.pc 123 pp.pc++ 124 } 125 126 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 { 127 q := pp.NewProg() 128 pp.clearp(q) 129 q.As = as 130 q.Pos = p.Pos 131 q.From.Type = ftype 132 q.From.Reg = freg 133 q.From.Offset = foffset 134 q.To.Type = ttype 135 q.To.Reg = treg 136 q.To.Offset = toffset 137 q.Link = p.Link 138 p.Link = q 139 return q 140 } 141 142 func (pp *Progs) settext(fn *Node) { 143 if pp.Text != nil { 144 Fatalf("Progs.settext called twice") 145 } 146 ptxt := pp.Prog(obj.ATEXT) 147 pp.Text = ptxt 148 149 if fn.Func.lsym == nil { 150 // func _() { } 151 return 152 } 153 154 fn.Func.lsym.Func.Text = ptxt 155 ptxt.From.Type = obj.TYPE_MEM 156 ptxt.From.Name = obj.NAME_EXTERN 157 ptxt.From.Sym = fn.Func.lsym 158 159 p := pp.Prog(obj.AFUNCDATA) 160 Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps) 161 p.To.Type = obj.TYPE_MEM 162 p.To.Name = obj.NAME_EXTERN 163 p.To.Sym = &fn.Func.lsym.Func.GCArgs 164 165 p = pp.Prog(obj.AFUNCDATA) 166 Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps) 167 p.To.Type = obj.TYPE_MEM 168 p.To.Name = obj.NAME_EXTERN 169 p.To.Sym = &fn.Func.lsym.Func.GCLocals 170 } 171 172 func (f *Func) initLSym() { 173 if f.lsym != nil { 174 Fatalf("Func.initLSym called twice") 175 } 176 177 if nam := f.Nname; !isblank(nam) { 178 f.lsym = nam.Sym.Linksym() 179 if f.Pragma&Systemstack != 0 { 180 f.lsym.Set(obj.AttrCFunc, true) 181 } 182 } 183 184 var flag int 185 if f.Dupok() { 186 flag |= obj.DUPOK 187 } 188 if f.Wrapper() { 189 flag |= obj.WRAPPER 190 } 191 if f.NoFramePointer() { 192 flag |= obj.NOFRAME 193 } 194 if f.Needctxt() { 195 flag |= obj.NEEDCTXT 196 } 197 if f.Pragma&Nosplit != 0 { 198 flag |= obj.NOSPLIT 199 } 200 if f.ReflectMethod() { 201 flag |= obj.REFLECTMETHOD 202 } 203 204 // Clumsy but important. 205 // See test/recover.go for test cases and src/reflect/value.go 206 // for the actual functions being considered. 207 if myimportpath == "reflect" { 208 switch f.Nname.Sym.Name { 209 case "callReflect", "callMethod": 210 flag |= obj.WRAPPER 211 } 212 } 213 214 Ctxt.InitTextSym(f.lsym, flag) 215 } 216 217 func ggloblnod(nam *Node) { 218 s := nam.Sym.Linksym() 219 s.Gotype = ngotype(nam).Linksym() 220 flags := 0 221 if nam.Name.Readonly() { 222 flags = obj.RODATA 223 } 224 if nam.Type != nil && !types.Haspointers(nam.Type) { 225 flags |= obj.NOPTR 226 } 227 Ctxt.Globl(s, nam.Type.Width, flags) 228 } 229 230 func ggloblsym(s *obj.LSym, width int32, flags int16) { 231 if flags&obj.LOCAL != 0 { 232 s.Set(obj.AttrLocal, true) 233 flags &^= obj.LOCAL 234 } 235 Ctxt.Globl(s, int64(width), int(flags)) 236 } 237 238 func isfat(t *types.Type) bool { 239 if t != nil { 240 switch t.Etype { 241 case TSTRUCT, TARRAY, TSLICE, TSTRING, 242 TINTER: // maybe remove later 243 return true 244 } 245 } 246 247 return false 248 } 249 250 func Addrconst(a *obj.Addr, v int64) { 251 a.Sym = nil 252 a.Type = obj.TYPE_CONST 253 a.Offset = v 254 } 255 256 func Patch(p *obj.Prog, to *obj.Prog) { 257 if p.To.Type != obj.TYPE_BRANCH { 258 Fatalf("patch: not a branch") 259 } 260 p.To.Val = to 261 p.To.Offset = to.Pc 262 }