github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 *[10000]obj.Prog = 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  	if pp.cacheidx < len(pp.progcache) {
    74  		p := &pp.progcache[pp.cacheidx]
    75  		p.Ctxt = Ctxt
    76  		pp.cacheidx++
    77  		return p
    78  	}
    79  	p := new(obj.Prog)
    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  }