...

Source file src/pkg/cmd/compile/internal/gc/gsubr.go

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

View as plain text