Source file src/cmd/compile/internal/escape/stmt.go

     1  // Copyright 2018 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  package escape
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"fmt"
    11  )
    12  
    13  // stmt evaluates a single Go statement.
    14  func (e *escape) stmt(n ir.Node) {
    15  	if n == nil {
    16  		return
    17  	}
    18  
    19  	lno := ir.SetPos(n)
    20  	defer func() {
    21  		base.Pos = lno
    22  	}()
    23  
    24  	if base.Flag.LowerM > 2 {
    25  		fmt.Printf("%v:[%d] %v stmt: %v\n", base.FmtPos(base.Pos), e.loopDepth, e.curfn, n)
    26  	}
    27  
    28  	e.stmts(n.Init())
    29  
    30  	switch n.Op() {
    31  	default:
    32  		base.Fatalf("unexpected stmt: %v", n)
    33  
    34  	case ir.OFALL, ir.OINLMARK:
    35  		// nop
    36  
    37  	case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
    38  		// TODO(mdempsky): Handle dead code?
    39  
    40  	case ir.OBLOCK:
    41  		n := n.(*ir.BlockStmt)
    42  		e.stmts(n.List)
    43  
    44  	case ir.ODCL:
    45  		// Record loop depth at declaration.
    46  		n := n.(*ir.Decl)
    47  		if !ir.IsBlank(n.X) {
    48  			e.dcl(n.X)
    49  		}
    50  
    51  	case ir.OLABEL:
    52  		n := n.(*ir.LabelStmt)
    53  		if n.Label.IsBlank() {
    54  			break
    55  		}
    56  		switch e.labels[n.Label] {
    57  		case nonlooping:
    58  			if base.Flag.LowerM > 2 {
    59  				fmt.Printf("%v:%v non-looping label\n", base.FmtPos(base.Pos), n)
    60  			}
    61  		case looping:
    62  			if base.Flag.LowerM > 2 {
    63  				fmt.Printf("%v: %v looping label\n", base.FmtPos(base.Pos), n)
    64  			}
    65  			e.loopDepth++
    66  		default:
    67  			base.Fatalf("label %v missing tag", n.Label)
    68  		}
    69  		delete(e.labels, n.Label)
    70  
    71  	case ir.OIF:
    72  		n := n.(*ir.IfStmt)
    73  		e.discard(n.Cond)
    74  		e.block(n.Body)
    75  		e.block(n.Else)
    76  
    77  	case ir.OCHECKNIL:
    78  		n := n.(*ir.UnaryExpr)
    79  		e.discard(n.X)
    80  
    81  	case ir.OFOR:
    82  		n := n.(*ir.ForStmt)
    83  		base.Assert(!n.DistinctVars) // Should all be rewritten before escape analysis
    84  		e.loopDepth++
    85  		e.discard(n.Cond)
    86  		e.stmt(n.Post)
    87  		e.block(n.Body)
    88  		e.loopDepth--
    89  
    90  	case ir.ORANGE:
    91  		// for Key, Value = range X { Body }
    92  		n := n.(*ir.RangeStmt)
    93  		base.Assert(!n.DistinctVars) // Should all be rewritten before escape analysis
    94  
    95  		// X is evaluated outside the loop and persists until the loop
    96  		// terminates.
    97  		tmp := e.newLoc(nil, true)
    98  		e.expr(tmp.asHole(), n.X)
    99  
   100  		e.loopDepth++
   101  		ks := e.addrs([]ir.Node{n.Key, n.Value})
   102  		if n.X.Type().IsArray() {
   103  			e.flow(ks[1].note(n, "range"), tmp)
   104  		} else {
   105  			e.flow(ks[1].deref(n, "range-deref"), tmp)
   106  		}
   107  		e.reassigned(ks, n)
   108  
   109  		e.block(n.Body)
   110  		e.loopDepth--
   111  
   112  	case ir.OSWITCH:
   113  		n := n.(*ir.SwitchStmt)
   114  
   115  		if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok {
   116  			var ks []hole
   117  			if guard.Tag != nil {
   118  				for _, cas := range n.Cases {
   119  					cv := cas.Var
   120  					k := e.dcl(cv) // type switch variables have no ODCL.
   121  					if cv.Type().HasPointers() {
   122  						ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
   123  					}
   124  				}
   125  			}
   126  			e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X)
   127  		} else {
   128  			e.discard(n.Tag)
   129  		}
   130  
   131  		for _, cas := range n.Cases {
   132  			e.discards(cas.List)
   133  			e.block(cas.Body)
   134  		}
   135  
   136  	case ir.OSELECT:
   137  		n := n.(*ir.SelectStmt)
   138  		for _, cas := range n.Cases {
   139  			e.stmt(cas.Comm)
   140  			e.block(cas.Body)
   141  		}
   142  	case ir.ORECV:
   143  		// TODO(mdempsky): Consider e.discard(n.Left).
   144  		n := n.(*ir.UnaryExpr)
   145  		e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
   146  	case ir.OSEND:
   147  		n := n.(*ir.SendStmt)
   148  		e.discard(n.Chan)
   149  		e.assignHeap(n.Value, "send", n)
   150  
   151  	case ir.OAS:
   152  		n := n.(*ir.AssignStmt)
   153  		e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
   154  	case ir.OASOP:
   155  		n := n.(*ir.AssignOpStmt)
   156  		// TODO(mdempsky): Worry about OLSH/ORSH?
   157  		e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
   158  	case ir.OAS2:
   159  		n := n.(*ir.AssignListStmt)
   160  		e.assignList(n.Lhs, n.Rhs, "assign-pair", n)
   161  
   162  	case ir.OAS2DOTTYPE: // v, ok = x.(type)
   163  		n := n.(*ir.AssignListStmt)
   164  		e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n)
   165  	case ir.OAS2MAPR: // v, ok = m[k]
   166  		n := n.(*ir.AssignListStmt)
   167  		e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n)
   168  	case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch
   169  		n := n.(*ir.AssignListStmt)
   170  		e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n)
   171  
   172  	case ir.OAS2FUNC:
   173  		n := n.(*ir.AssignListStmt)
   174  		e.stmts(n.Rhs[0].Init())
   175  		ks := e.addrs(n.Lhs)
   176  		e.call(ks, n.Rhs[0])
   177  		e.reassigned(ks, n)
   178  	case ir.ORETURN:
   179  		n := n.(*ir.ReturnStmt)
   180  		results := e.curfn.Type().Results()
   181  		dsts := make([]ir.Node, len(results))
   182  		for i, res := range results {
   183  			dsts[i] = res.Nname.(*ir.Name)
   184  		}
   185  		e.assignList(dsts, n.Results, "return", n)
   186  	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OINLCALL, ir.OCLEAR, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTLN, ir.ORECOVERFP:
   187  		e.call(nil, n)
   188  	case ir.OGO, ir.ODEFER:
   189  		n := n.(*ir.GoDeferStmt)
   190  		e.goDeferStmt(n)
   191  
   192  	case ir.OTAILCALL:
   193  		n := n.(*ir.TailCallStmt)
   194  		e.call(nil, n.Call)
   195  	}
   196  }
   197  
   198  func (e *escape) stmts(l ir.Nodes) {
   199  	for _, n := range l {
   200  		e.stmt(n)
   201  	}
   202  }
   203  
   204  // block is like stmts, but preserves loopDepth.
   205  func (e *escape) block(l ir.Nodes) {
   206  	old := e.loopDepth
   207  	e.stmts(l)
   208  	e.loopDepth = old
   209  }
   210  
   211  func (e *escape) dcl(n *ir.Name) hole {
   212  	if n.Curfn != e.curfn || n.IsClosureVar() {
   213  		base.Fatalf("bad declaration of %v", n)
   214  	}
   215  	loc := e.oldLoc(n)
   216  	loc.loopDepth = e.loopDepth
   217  	return loc.asHole()
   218  }
   219  

View as plain text