github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/gc/gen.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Portable half of code generator; mainly statements and control flow.
     6  
     7  package gc
     8  
     9  import (
    10  	"cmd/internal/obj"
    11  	"fmt"
    12  )
    13  
    14  func Sysfunc(name string) *obj.LSym {
    15  	return Linksym(Pkglookup(name, Runtimepkg))
    16  }
    17  
    18  // addrescapes tags node n as having had its address taken
    19  // by "increasing" the "value" of n.Esc to EscHeap.
    20  // Storage is allocated as necessary to allow the address
    21  // to be taken.
    22  func addrescapes(n *Node) {
    23  	switch n.Op {
    24  	// probably a type error already.
    25  	// dump("addrescapes", n);
    26  	default:
    27  		break
    28  
    29  	case ONAME:
    30  		if n == nodfp {
    31  			break
    32  		}
    33  
    34  		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
    35  		// on PPARAM it means something different.
    36  		if n.Class == PAUTO && n.Esc == EscNever {
    37  			break
    38  		}
    39  
    40  		// If a closure reference escapes, mark the outer variable as escaping.
    41  		if n.isClosureVar() {
    42  			addrescapes(n.Name.Defn)
    43  			break
    44  		}
    45  
    46  		if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
    47  			break
    48  		}
    49  
    50  		// This is a plain parameter or local variable that needs to move to the heap,
    51  		// but possibly for the function outside the one we're compiling.
    52  		// That is, if we have:
    53  		//
    54  		//	func f(x int) {
    55  		//		func() {
    56  		//			global = &x
    57  		//		}
    58  		//	}
    59  		//
    60  		// then we're analyzing the inner closure but we need to move x to the
    61  		// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
    62  		oldfn := Curfn
    63  		Curfn = n.Name.Curfn
    64  		if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
    65  			Curfn = Curfn.Func.Closure
    66  		}
    67  		ln := lineno
    68  		lineno = Curfn.Pos
    69  		moveToHeap(n)
    70  		Curfn = oldfn
    71  		lineno = ln
    72  
    73  	case OIND, ODOTPTR:
    74  		break
    75  
    76  	// ODOTPTR has already been introduced,
    77  	// so these are the non-pointer ODOT and OINDEX.
    78  	// In &x[0], if x is a slice, then x does not
    79  	// escape--the pointer inside x does, but that
    80  	// is always a heap pointer anyway.
    81  	case ODOT, OINDEX, OPAREN, OCONVNOP:
    82  		if !n.Left.Type.IsSlice() {
    83  			addrescapes(n.Left)
    84  		}
    85  	}
    86  }
    87  
    88  // isParamStackCopy reports whether this is the on-stack copy of a
    89  // function parameter that moved to the heap.
    90  func (n *Node) isParamStackCopy() bool {
    91  	return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Param.Heapaddr != nil
    92  }
    93  
    94  // isParamHeapCopy reports whether this is the on-heap copy of
    95  // a function parameter that moved to the heap.
    96  func (n *Node) isParamHeapCopy() bool {
    97  	return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil
    98  }
    99  
   100  // moveToHeap records the parameter or local variable n as moved to the heap.
   101  func moveToHeap(n *Node) {
   102  	if Debug['r'] != 0 {
   103  		Dump("MOVE", n)
   104  	}
   105  	if compiling_runtime {
   106  		yyerror("%v escapes to heap, not allowed in runtime.", n)
   107  	}
   108  	if n.Class == PAUTOHEAP {
   109  		Dump("n", n)
   110  		Fatalf("double move to heap")
   111  	}
   112  
   113  	// Allocate a local stack variable to hold the pointer to the heap copy.
   114  	// temp will add it to the function declaration list automatically.
   115  	heapaddr := temp(ptrto(n.Type))
   116  	heapaddr.Sym = lookup("&" + n.Sym.Name)
   117  	heapaddr.Orig.Sym = heapaddr.Sym
   118  
   119  	// Unset AutoTemp to persist the &foo variable name through SSA to
   120  	// liveness analysis.
   121  	// TODO(mdempsky/drchase): Cleaner solution?
   122  	heapaddr.Name.AutoTemp = false
   123  
   124  	// Parameters have a local stack copy used at function start/end
   125  	// in addition to the copy in the heap that may live longer than
   126  	// the function.
   127  	if n.Class == PPARAM || n.Class == PPARAMOUT {
   128  		if n.Xoffset == BADWIDTH {
   129  			Fatalf("addrescapes before param assignment")
   130  		}
   131  
   132  		// We rewrite n below to be a heap variable (indirection of heapaddr).
   133  		// Preserve a copy so we can still write code referring to the original,
   134  		// and substitute that copy into the function declaration list
   135  		// so that analyses of the local (on-stack) variables use it.
   136  		stackcopy := nod(ONAME, nil, nil)
   137  		stackcopy.Sym = n.Sym
   138  		stackcopy.Type = n.Type
   139  		stackcopy.Xoffset = n.Xoffset
   140  		stackcopy.Class = n.Class
   141  		stackcopy.Name.Param.Heapaddr = heapaddr
   142  		if n.Class == PPARAMOUT {
   143  			// Make sure the pointer to the heap copy is kept live throughout the function.
   144  			// The function could panic at any point, and then a defer could recover.
   145  			// Thus, we need the pointer to the heap copy always available so the
   146  			// post-deferreturn code can copy the return value back to the stack.
   147  			// See issue 16095.
   148  			heapaddr.setIsOutputParamHeapAddr(true)
   149  		}
   150  		n.Name.Param.Stackcopy = stackcopy
   151  
   152  		// Substitute the stackcopy into the function variable list so that
   153  		// liveness and other analyses use the underlying stack slot
   154  		// and not the now-pseudo-variable n.
   155  		found := false
   156  		for i, d := range Curfn.Func.Dcl {
   157  			if d == n {
   158  				Curfn.Func.Dcl[i] = stackcopy
   159  				found = true
   160  				break
   161  			}
   162  			// Parameters are before locals, so can stop early.
   163  			// This limits the search even in functions with many local variables.
   164  			if d.Class == PAUTO {
   165  				break
   166  			}
   167  		}
   168  		if !found {
   169  			Fatalf("cannot find %v in local variable list", n)
   170  		}
   171  		Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   172  	}
   173  
   174  	// Modify n in place so that uses of n now mean indirection of the heapaddr.
   175  	n.Class = PAUTOHEAP
   176  	n.Ullman = 2
   177  	n.Xoffset = 0
   178  	n.Name.Param.Heapaddr = heapaddr
   179  	n.Esc = EscHeap
   180  	if Debug['m'] != 0 {
   181  		fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
   182  	}
   183  }
   184  
   185  // make a new Node off the books
   186  func tempname(nn *Node, t *Type) {
   187  	if Curfn == nil {
   188  		Fatalf("no curfn for tempname")
   189  	}
   190  	if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
   191  		Dump("tempname", Curfn)
   192  		Fatalf("adding tempname to wrong closure function")
   193  	}
   194  
   195  	if t == nil {
   196  		yyerror("tempname called with nil type")
   197  		t = Types[TINT32]
   198  	}
   199  
   200  	// give each tmp a different name so that there
   201  	// a chance to registerizer them.
   202  	// Add a preceding . to avoid clash with legal names.
   203  	s := lookupN(".autotmp_", statuniqgen)
   204  	statuniqgen++
   205  	n := nod(ONAME, nil, nil)
   206  	n.Sym = s
   207  	s.Def = n
   208  	n.Type = t
   209  	n.Class = PAUTO
   210  	n.Addable = true
   211  	n.Ullman = 1
   212  	n.Esc = EscNever
   213  	n.Name.Curfn = Curfn
   214  	n.Name.AutoTemp = true
   215  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   216  
   217  	dowidth(t)
   218  	n.Xoffset = 0
   219  	*nn = *n
   220  }
   221  
   222  func temp(t *Type) *Node {
   223  	var n Node
   224  	tempname(&n, t)
   225  	n.Sym.Def.Used = true
   226  	return n.Orig
   227  }