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