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 ([email protected]) 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 ([email protected]) 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 31package objw 32 33import ( 34 "cmd/compile/internal/base" 35 "cmd/compile/internal/ir" 36 "cmd/internal/obj" 37 "cmd/internal/src" 38 "internal/abi" 39) 40 41var 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. 45func 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 = -1 61 pp.NextLive = pp.PrevLive 62 pp.NextUnsafe = pp.PrevUnsafe 63 return pp 64} 65 66// Progs accumulates Progs for a function and converts them into machine code. 67type Progs struct { 68 Text *obj.Prog // ATEXT Prog for this function 69 Next *obj.Prog // next Prog 70 PC int64 // virtual PC; count of Progs 71 Pos src.XPos // position to use for new Progs 72 CurFunc *ir.Func // fn these Progs are for 73 Cache []obj.Prog // local progcache 74 CacheIndex int // first free element of progcache 75 76 NextLive StackMapIndex // liveness index for the next Prog 77 PrevLive StackMapIndex // last emitted liveness index 78 79 NextUnsafe bool // unsafe mark for the next Prog 80 PrevUnsafe bool // last emitted unsafe mark 81} 82 83type StackMapIndex int 84 85// StackMapDontCare indicates that the stack map index at a Value 86// doesn't matter. 87// 88// This is a sentinel value that should never be emitted to the PCDATA 89// stream. We use -1000 because that's obviously never a valid stack 90// index (but -1 is). 91const StackMapDontCare StackMapIndex = -1000 92 93func (s StackMapIndex) StackMapValid() bool { 94 return s != StackMapDontCare 95} 96 97func (pp *Progs) NewProg() *obj.Prog { 98 var p *obj.Prog 99 if pp.CacheIndex < len(pp.Cache) { 100 p = &pp.Cache[pp.CacheIndex] 101 pp.CacheIndex++ 102 } else { 103 p = new(obj.Prog) 104 } 105 p.Ctxt = base.Ctxt 106 return p 107} 108 109// Flush converts from pp to machine code. 110func (pp *Progs) Flush() { 111 plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.CurFunc} 112 obj.Flushplist(base.Ctxt, plist, pp.NewProg) 113} 114 115// Free clears pp and any associated resources. 116func (pp *Progs) Free() { 117 if base.Ctxt.CanReuseProgs() { 118 // Clear progs to enable GC and avoid abuse. 119 s := pp.Cache[:pp.CacheIndex] 120 for i := range s { 121 s[i] = obj.Prog{} 122 } 123 } 124 // Clear pp to avoid abuse. 125 *pp = Progs{} 126} 127 128// Prog adds a Prog with instruction As to pp. 129func (pp *Progs) Prog(as obj.As) *obj.Prog { 130 if pp.NextLive != StackMapDontCare && pp.NextLive != pp.PrevLive { 131 // Emit stack map index change. 132 idx := pp.NextLive 133 pp.PrevLive = idx 134 p := pp.Prog(obj.APCDATA) 135 p.From.SetConst(abi.PCDATA_StackMapIndex) 136 p.To.SetConst(int64(idx)) 137 } 138 if pp.NextUnsafe != pp.PrevUnsafe { 139 // Emit unsafe-point marker. 140 pp.PrevUnsafe = pp.NextUnsafe 141 p := pp.Prog(obj.APCDATA) 142 p.From.SetConst(abi.PCDATA_UnsafePoint) 143 if pp.NextUnsafe { 144 p.To.SetConst(abi.UnsafePointUnsafe) 145 } else { 146 p.To.SetConst(abi.UnsafePointSafe) 147 } 148 } 149 150 p := pp.Next 151 pp.Next = pp.NewProg() 152 pp.Clear(pp.Next) 153 p.Link = pp.Next 154 155 if !pp.Pos.IsKnown() && base.Flag.K != 0 { 156 base.Warn("prog: unknown position (line 0)") 157 } 158 159 p.As = as 160 p.Pos = pp.Pos 161 if pp.Pos.IsStmt() == src.PosIsStmt { 162 // Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt 163 if LosesStmtMark(as) { 164 return p 165 } 166 pp.Pos = pp.Pos.WithNotStmt() 167 } 168 return p 169} 170 171func (pp *Progs) Clear(p *obj.Prog) { 172 obj.Nopout(p) 173 p.As = obj.AEND 174 p.Pc = pp.PC 175 pp.PC++ 176} 177 178func (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 { 179 q := pp.NewProg() 180 pp.Clear(q) 181 q.As = as 182 q.Pos = p.Pos 183 q.From.Type = ftype 184 q.From.Reg = freg 185 q.From.Offset = foffset 186 q.To.Type = ttype 187 q.To.Reg = treg 188 q.To.Offset = toffset 189 q.Link = p.Link 190 p.Link = q 191 return q 192} 193 194func (pp *Progs) SetText(fn *ir.Func) { 195 if pp.Text != nil { 196 base.Fatalf("Progs.SetText called twice") 197 } 198 ptxt := pp.Prog(obj.ATEXT) 199 pp.Text = ptxt 200 201 fn.LSym.Func().Text = ptxt 202 ptxt.From.Type = obj.TYPE_MEM 203 ptxt.From.Name = obj.NAME_EXTERN 204 ptxt.From.Sym = fn.LSym 205} 206 207// LosesStmtMark reports whether a prog with op as loses its statement mark on the way to DWARF. 208// The attributes from some opcodes are lost in translation. 209// TODO: this is an artifact of how funcpctab combines information for instructions at a single PC. 210// Should try to fix it there. 211func LosesStmtMark(as obj.As) bool { 212 // is_stmt does not work for these; it DOES for ANOP even though that generates no code. 213 return as == obj.APCDATA || as == obj.AFUNCDATA 214} 215