2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// "Portable" code generation.
|
|
|
|
|
// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
|
|
|
|
|
// Must code to the intersection of the three back ends.
|
|
|
|
|
|
|
|
|
|
//#include "opt.h"
|
|
|
|
|
|
|
|
|
|
var makefuncdatasym_nsym int32
|
|
|
|
|
|
|
|
|
|
func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
|
|
|
|
|
var nod Node
|
|
|
|
|
|
|
|
|
|
namebuf = fmt.Sprintf(namefmt, makefuncdatasym_nsym)
|
|
|
|
|
makefuncdatasym_nsym++
|
2015-02-23 16:07:24 -05:00
|
|
|
sym := Lookup(namebuf)
|
|
|
|
|
pnod := newname(sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
pnod.Class = PEXTERN
|
|
|
|
|
Nodconst(&nod, Types[TINT32], funcdatakind)
|
|
|
|
|
Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
|
|
|
|
|
return sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gvardef inserts a VARDEF for n into the instruction stream.
|
|
|
|
|
// VARDEF is an annotation for the liveness analysis, marking a place
|
|
|
|
|
// where a complete initialization (definition) of a variable begins.
|
|
|
|
|
// Since the liveness analysis can see initialization of single-word
|
|
|
|
|
// variables quite easy, gvardef is usually only called for multi-word
|
|
|
|
|
// or 'fat' variables, those satisfying isfat(n->type).
|
|
|
|
|
// However, gvardef is also called when a non-fat variable is initialized
|
|
|
|
|
// via a block move; the only time this happens is when you have
|
|
|
|
|
// return f()
|
|
|
|
|
// for a function with multiple return values exactly matching the return
|
|
|
|
|
// types of the current function.
|
|
|
|
|
//
|
|
|
|
|
// A 'VARDEF x' annotation in the instruction stream tells the liveness
|
|
|
|
|
// analysis to behave as though the variable x is being initialized at that
|
|
|
|
|
// point in the instruction stream. The VARDEF must appear before the
|
|
|
|
|
// actual (multi-instruction) initialization, and it must also appear after
|
|
|
|
|
// any uses of the previous value, if any. For example, if compiling:
|
|
|
|
|
//
|
|
|
|
|
// x = x[1:]
|
|
|
|
|
//
|
|
|
|
|
// it is important to generate code like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// If instead the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis would decide the previous value of x was
|
|
|
|
|
// unnecessary even though it is about to be used by the x[1:] computation.
|
|
|
|
|
// Similarly, if the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
// VARDEF x
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis will not preserve the new value of x, because
|
|
|
|
|
// the VARDEF appears to have "overwritten" it.
|
|
|
|
|
//
|
|
|
|
|
// VARDEF is a bit of a kludge to work around the fact that the instruction
|
|
|
|
|
// stream is working on single-word values but the liveness analysis
|
|
|
|
|
// wants to work on individual variables, which might be multi-word
|
|
|
|
|
// aggregates. It might make sense at some point to look into letting
|
|
|
|
|
// the liveness analysis work on single-word values as well, although
|
|
|
|
|
// there are complications around interface values, slices, and strings,
|
|
|
|
|
// all of which cannot be treated as individual words.
|
|
|
|
|
//
|
|
|
|
|
// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
|
|
|
|
|
// even if its address has been taken. That is, a VARKILL annotation asserts
|
|
|
|
|
// that its argument is certainly dead, for use when the liveness analysis
|
|
|
|
|
// would not otherwise be able to deduce that fact.
|
|
|
|
|
|
|
|
|
|
func gvardefx(n *Node, as int) {
|
|
|
|
|
if n == nil {
|
|
|
|
|
Fatal("gvardef nil")
|
|
|
|
|
}
|
|
|
|
|
if n.Op != ONAME {
|
|
|
|
|
Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n, 0))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Class {
|
|
|
|
|
case PAUTO,
|
|
|
|
|
PPARAM,
|
|
|
|
|
PPARAMOUT:
|
|
|
|
|
Thearch.Gins(as, nil, n)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Gvardef(n *Node) {
|
|
|
|
|
gvardefx(n, obj.AVARDEF)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gvarkill(n *Node) {
|
|
|
|
|
gvardefx(n, obj.AVARKILL)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func removevardef(firstp *obj.Prog) {
|
2015-02-23 16:07:24 -05:00
|
|
|
for p := firstp; p != nil; p = p.Link {
|
2015-02-13 14:40:36 -05:00
|
|
|
for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
|
|
|
|
|
p.Link = p.Link.Link
|
|
|
|
|
}
|
|
|
|
|
if p.To.Type == obj.TYPE_BRANCH {
|
|
|
|
|
for p.To.U.Branch != nil && (p.To.U.Branch.As == obj.AVARDEF || p.To.U.Branch.As == obj.AVARKILL) {
|
|
|
|
|
p.To.U.Branch = p.To.U.Branch.Link
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gcsymdup(s *Sym) {
|
2015-02-23 16:07:24 -05:00
|
|
|
ls := Linksym(s)
|
2015-02-13 14:40:36 -05:00
|
|
|
if len(ls.R) > 0 {
|
|
|
|
|
Fatal("cannot rosymdup %s with relocations", ls.Name)
|
|
|
|
|
}
|
|
|
|
|
var d MD5
|
|
|
|
|
md5reset(&d)
|
|
|
|
|
md5write(&d, ls.P, len(ls.P))
|
2015-02-23 16:07:24 -05:00
|
|
|
var hi uint64
|
|
|
|
|
lo := md5sum(&d, &hi)
|
2015-02-13 14:40:36 -05:00
|
|
|
ls.Name = fmt.Sprintf("gclocals·%016x%016x", lo, hi)
|
|
|
|
|
ls.Dupok = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func emitptrargsmap() {
|
2015-02-23 16:07:24 -05:00
|
|
|
sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Nname.Sym.Name))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
nptr := int(Curfn.Type.Argwid / int64(Widthptr))
|
|
|
|
|
bv := bvalloc(int32(nptr) * 2)
|
|
|
|
|
nbitmap := 1
|
2015-02-13 14:40:36 -05:00
|
|
|
if Curfn.Type.Outtuple > 0 {
|
|
|
|
|
nbitmap = 2
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
off := duint32(sym, 0, uint32(nbitmap))
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, uint32(bv.n))
|
2015-02-23 16:07:24 -05:00
|
|
|
var xoffset int64
|
2015-02-13 14:40:36 -05:00
|
|
|
if Curfn.Type.Thistuple > 0 {
|
|
|
|
|
xoffset = 0
|
|
|
|
|
twobitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Curfn.Type.Intuple > 0 {
|
|
|
|
|
xoffset = 0
|
|
|
|
|
twobitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for j := 0; int32(j) < bv.n; j += 32 {
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, bv.b[j/32])
|
|
|
|
|
}
|
|
|
|
|
if Curfn.Type.Outtuple > 0 {
|
|
|
|
|
xoffset = 0
|
|
|
|
|
twobitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
|
2015-02-23 16:07:24 -05:00
|
|
|
for j := 0; int32(j) < bv.n; j += 32 {
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, bv.b[j/32])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ggloblsym(sym, int32(off), obj.RODATA)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort the list of stack variables. Autos after anything else,
|
|
|
|
|
// within autos, unused after used, within used, things with
|
|
|
|
|
// pointers first, zeroed things first, and then decreasing size.
|
|
|
|
|
// Because autos are laid out in decreasing addresses
|
|
|
|
|
// on the stack, pointers first, zeroed things first and decreasing size
|
|
|
|
|
// really means, in memory, things with pointers needing zeroing at
|
|
|
|
|
// the top of the stack and increasing in size.
|
|
|
|
|
// Non-autos sort on offset.
|
|
|
|
|
func cmpstackvar(a *Node, b *Node) int {
|
|
|
|
|
if a.Class != b.Class {
|
|
|
|
|
if a.Class == PAUTO {
|
|
|
|
|
return +1
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Class != PAUTO {
|
|
|
|
|
if a.Xoffset < b.Xoffset {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
if a.Xoffset > b.Xoffset {
|
|
|
|
|
return +1
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a.Used == 0) != (b.Used == 0) {
|
|
|
|
|
return int(b.Used) - int(a.Used)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ap := bool2int(haspointers(a.Type))
|
|
|
|
|
bp := bool2int(haspointers(b.Type))
|
2015-02-13 14:40:36 -05:00
|
|
|
if ap != bp {
|
|
|
|
|
return bp - ap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ap = int(a.Needzero)
|
|
|
|
|
bp = int(b.Needzero)
|
|
|
|
|
if ap != bp {
|
|
|
|
|
return bp - ap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Type.Width < b.Type.Width {
|
|
|
|
|
return +1
|
|
|
|
|
}
|
|
|
|
|
if a.Type.Width > b.Type.Width {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stringsCompare(a.Sym.Name, b.Sym.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
|
|
|
|
|
func allocauto(ptxt *obj.Prog) {
|
|
|
|
|
Stksize = 0
|
|
|
|
|
stkptrsize = 0
|
|
|
|
|
|
|
|
|
|
if Curfn.Dcl == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mark the PAUTO's unused.
|
2015-02-23 16:07:24 -05:00
|
|
|
for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if ll.N.Class == PAUTO {
|
|
|
|
|
ll.N.Used = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
markautoused(ptxt)
|
|
|
|
|
|
|
|
|
|
listsort(&Curfn.Dcl, cmpstackvar)
|
|
|
|
|
|
|
|
|
|
// Unused autos are at the end, chop 'em off.
|
2015-02-23 16:07:24 -05:00
|
|
|
ll := Curfn.Dcl
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
n := ll.N
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
// No locals used at all
|
|
|
|
|
Curfn.Dcl = nil
|
|
|
|
|
|
|
|
|
|
fixautoused(ptxt)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for ll := Curfn.Dcl; ll.Next != nil; ll = ll.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = ll.Next.N
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
ll.Next = nil
|
|
|
|
|
Curfn.Dcl.End = ll
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reassign stack offsets of the locals that are still there.
|
2015-02-23 16:07:24 -05:00
|
|
|
var w int64
|
|
|
|
|
for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = ll.N
|
|
|
|
|
if n.Class != PAUTO || n.Op != ONAME {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dowidth(n.Type)
|
|
|
|
|
w = n.Type.Width
|
|
|
|
|
if w >= Thearch.MAXWIDTH || w < 0 {
|
|
|
|
|
Fatal("bad width")
|
|
|
|
|
}
|
|
|
|
|
Stksize += w
|
|
|
|
|
Stksize = Rnd(Stksize, int64(n.Type.Align))
|
|
|
|
|
if haspointers(n.Type) {
|
|
|
|
|
stkptrsize = Stksize
|
|
|
|
|
}
|
|
|
|
|
if Thearch.Thechar == '5' || Thearch.Thechar == '9' {
|
|
|
|
|
Stksize = Rnd(Stksize, int64(Widthptr))
|
|
|
|
|
}
|
|
|
|
|
if Stksize >= 1<<31 {
|
|
|
|
|
setlineno(Curfn)
|
|
|
|
|
Yyerror("stack frame too large (>2GB)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n.Stkdelta = -Stksize - n.Xoffset
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stksize = Rnd(Stksize, int64(Widthreg))
|
|
|
|
|
stkptrsize = Rnd(stkptrsize, int64(Widthreg))
|
|
|
|
|
|
|
|
|
|
fixautoused(ptxt)
|
|
|
|
|
|
|
|
|
|
// The debug information needs accurate offsets on the symbols.
|
2015-02-23 16:07:24 -05:00
|
|
|
for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if ll.N.Class != PAUTO || ll.N.Op != ONAME {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ll.N.Xoffset += ll.N.Stkdelta
|
|
|
|
|
ll.N.Stkdelta = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func movelarge(l *NodeList) {
|
|
|
|
|
for ; l != nil; l = l.Next {
|
|
|
|
|
if l.N.Op == ODCLFUNC {
|
|
|
|
|
movelargefn(l.N)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func movelargefn(fn *Node) {
|
|
|
|
|
var n *Node
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := fn.Dcl; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = l.N
|
|
|
|
|
if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize {
|
|
|
|
|
addrescapes(n)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Cgen_checknil(n *Node) {
|
|
|
|
|
if Disable_checknil != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ideally we wouldn't see any integer types here, but we do.
|
2015-03-01 07:54:01 +00:00
|
|
|
if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Dump("checknil", n)
|
|
|
|
|
Fatal("bad checknil")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if ((Thearch.Thechar == '5' || Thearch.Thechar == '9') && n.Op != OREGISTER) || n.Addable == 0 || n.Op == OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
var reg Node
|
2015-02-13 14:40:36 -05:00
|
|
|
Thearch.Regalloc(®, Types[Tptr], n)
|
|
|
|
|
Thearch.Cgen(n, ®)
|
|
|
|
|
Thearch.Gins(obj.ACHECKNIL, ®, nil)
|
|
|
|
|
Thearch.Regfree(®)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Gins(obj.ACHECKNIL, n, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ggen.c
|
|
|
|
|
*/
|
|
|
|
|
func compile(fn *Node) {
|
|
|
|
|
if Newproc == nil {
|
|
|
|
|
Newproc = Sysfunc("newproc")
|
|
|
|
|
Deferproc = Sysfunc("deferproc")
|
|
|
|
|
Deferreturn = Sysfunc("deferreturn")
|
|
|
|
|
Panicindex = Sysfunc("panicindex")
|
|
|
|
|
panicslice = Sysfunc("panicslice")
|
|
|
|
|
throwreturn = Sysfunc("throwreturn")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := setlineno(fn)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
Curfn = fn
|
|
|
|
|
dowidth(Curfn.Type)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var oldstksize int64
|
|
|
|
|
var nod1 Node
|
|
|
|
|
var ptxt *obj.Prog
|
|
|
|
|
var pl *obj.Plist
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
var n *Node
|
|
|
|
|
var nam *Node
|
|
|
|
|
var gcargs *Sym
|
|
|
|
|
var gclocals *Sym
|
2015-02-13 14:40:36 -05:00
|
|
|
if fn.Nbody == nil {
|
2015-02-20 13:54:45 -05:00
|
|
|
if pure_go != 0 || strings.HasPrefix(fn.Nname.Sym.Name, "init.") {
|
2015-02-27 20:42:18 +01:00
|
|
|
Yyerror("missing function body for %q", fn.Nname.Sym.Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Debug['A'] != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
emitptrargsmap()
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveerrors()
|
|
|
|
|
|
|
|
|
|
// set up domain for labels
|
|
|
|
|
clearlabels()
|
|
|
|
|
|
|
|
|
|
if Curfn.Type.Outnamed != 0 {
|
|
|
|
|
// add clearing of the output parameters
|
2015-02-23 16:07:24 -05:00
|
|
|
var save Iter
|
|
|
|
|
t := Structfirst(&save, Getoutarg(Curfn.Type))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
for t != nil {
|
|
|
|
|
if t.Nname != nil {
|
|
|
|
|
n = Nod(OAS, t.Nname, nil)
|
|
|
|
|
typecheck(&n, Etop)
|
|
|
|
|
Curfn.Nbody = concat(list1(n), Curfn.Nbody)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t = structnext(&save)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order(Curfn)
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Hasdefer = 0
|
|
|
|
|
walk(Curfn)
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
if flag_race != 0 {
|
|
|
|
|
racewalk(Curfn)
|
|
|
|
|
}
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continpc = nil
|
|
|
|
|
breakpc = nil
|
|
|
|
|
|
|
|
|
|
pl = newplist()
|
|
|
|
|
pl.Name = Linksym(Curfn.Nname.Sym)
|
|
|
|
|
|
|
|
|
|
setlineno(Curfn)
|
|
|
|
|
|
|
|
|
|
Nodconst(&nod1, Types[TINT32], 0)
|
|
|
|
|
nam = Curfn.Nname
|
|
|
|
|
if isblank(nam) {
|
|
|
|
|
nam = nil
|
|
|
|
|
}
|
|
|
|
|
ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
|
|
|
|
|
if fn.Dupok != 0 {
|
|
|
|
|
ptxt.From3.Offset |= obj.DUPOK
|
|
|
|
|
}
|
|
|
|
|
if fn.Wrapper != 0 {
|
|
|
|
|
ptxt.From3.Offset |= obj.WRAPPER
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if fn.Needctxt {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.NEEDCTXT
|
|
|
|
|
}
|
|
|
|
|
if fn.Nosplit {
|
|
|
|
|
ptxt.From3.Offset |= obj.NOSPLIT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clumsy but important.
|
|
|
|
|
// See test/recover.go for test cases and src/reflect/value.go
|
|
|
|
|
// for the actual functions being considered.
|
|
|
|
|
if myimportpath != "" && myimportpath == "reflect" {
|
|
|
|
|
if Curfn.Nname.Sym.Name == "callReflect" || Curfn.Nname.Sym.Name == "callMethod" {
|
|
|
|
|
ptxt.From3.Offset |= obj.WRAPPER
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Afunclit(&ptxt.From, Curfn.Nname)
|
|
|
|
|
|
|
|
|
|
Thearch.Ginit()
|
|
|
|
|
|
|
|
|
|
gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
|
|
|
|
|
gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for t := Curfn.Paramfld; t != nil; t = t.Down {
|
2015-02-13 14:40:36 -05:00
|
|
|
gtrack(tracksym(t.Type))
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := fn.Dcl; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = l.N
|
|
|
|
|
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
switch n.Class {
|
|
|
|
|
case PAUTO,
|
|
|
|
|
PPARAM,
|
|
|
|
|
PPARAMOUT:
|
|
|
|
|
Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
|
|
|
|
|
p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
|
|
|
|
|
p.From.Gotype = Linksym(ngotype(l.N))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Genlist(Curfn.Enter)
|
|
|
|
|
Genlist(Curfn.Nbody)
|
|
|
|
|
Thearch.Gclean()
|
|
|
|
|
checklabels()
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
if Curfn.Endlineno != 0 {
|
|
|
|
|
lineno = Curfn.Endlineno
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Curfn.Type.Outtuple != 0 {
|
|
|
|
|
Thearch.Ginscall(throwreturn, 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Ginit()
|
|
|
|
|
|
|
|
|
|
// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
|
|
|
|
|
Thearch.Cgen_ret(nil)
|
|
|
|
|
|
|
|
|
|
if Hasdefer != 0 {
|
|
|
|
|
// deferreturn pretends to have one uintptr argument.
|
|
|
|
|
// Reserve space for it so stack scanner is happy.
|
|
|
|
|
if Maxarg < int64(Widthptr) {
|
|
|
|
|
Maxarg = int64(Widthptr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Gclean()
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pc.As = obj.ARET // overwrite AEND
|
|
|
|
|
Pc.Lineno = lineno
|
|
|
|
|
|
|
|
|
|
fixjmp(ptxt)
|
2015-02-17 22:13:49 -05:00
|
|
|
if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
regopt(ptxt)
|
|
|
|
|
nilopt(ptxt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Expandchecks(ptxt)
|
|
|
|
|
|
|
|
|
|
oldstksize = Stksize
|
|
|
|
|
allocauto(ptxt)
|
|
|
|
|
|
|
|
|
|
if false {
|
|
|
|
|
fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setlineno(Curfn)
|
|
|
|
|
if int64(Stksize)+Maxarg > 1<<31 {
|
|
|
|
|
Yyerror("stack frame too large (>2GB)")
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit garbage collection symbols.
|
|
|
|
|
liveness(Curfn, ptxt, gcargs, gclocals)
|
|
|
|
|
|
|
|
|
|
gcsymdup(gcargs)
|
|
|
|
|
gcsymdup(gclocals)
|
|
|
|
|
|
|
|
|
|
Thearch.Defframe(ptxt)
|
|
|
|
|
|
|
|
|
|
if Debug['f'] != 0 {
|
|
|
|
|
frame(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove leftover instrumentation from the instruction stream.
|
|
|
|
|
removevardef(ptxt)
|
|
|
|
|
|
|
|
|
|
ret:
|
|
|
|
|
lineno = lno
|
|
|
|
|
}
|