Home | History | Annotate | Download | only in gc
      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 (a] 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 (a] 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, myimportpath)
     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 }
    263