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.ODCLCONST, ir.ODCLTYPE, 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  		switch e.labels[n.Label] {
    54  		case nonlooping:
    55  			if base.Flag.LowerM > 2 {
    56  				fmt.Printf("%v:%v non-looping label\n", base.FmtPos(base.Pos), n)
    57  			}
    58  		case looping:
    59  			if base.Flag.LowerM > 2 {
    60  				fmt.Printf("%v: %v looping label\n", base.FmtPos(base.Pos), n)
    61  			}
    62  			e.loopDepth++
    63  		default:
    64  			base.Fatalf("label missing tag")
    65  		}
    66  		delete(e.labels, n.Label)
    67  
    68  	case ir.OIF:
    69  		n := n.(*ir.IfStmt)
    70  		e.discard(n.Cond)
    71  		e.block(n.Body)
    72  		e.block(n.Else)
    73  
    74  	case ir.OFOR, ir.OFORUNTIL:
    75  		n := n.(*ir.ForStmt)
    76  		e.loopDepth++
    77  		e.discard(n.Cond)
    78  		e.stmt(n.Post)
    79  		e.block(n.Body)
    80  		e.loopDepth--
    81  
    82  	case ir.ORANGE:
    83  		// for Key, Value = range X { Body }
    84  		n := n.(*ir.RangeStmt)
    85  
    86  		// X is evaluated outside the loop.
    87  		tmp := e.newLoc(nil, false)
    88  		e.expr(tmp.asHole(), n.X)
    89  
    90  		e.loopDepth++
    91  		ks := e.addrs([]ir.Node{n.Key, n.Value})
    92  		if n.X.Type().IsArray() {
    93  			e.flow(ks[1].note(n, "range"), tmp)
    94  		} else {
    95  			e.flow(ks[1].deref(n, "range-deref"), tmp)
    96  		}
    97  		e.reassigned(ks, n)
    98  
    99  		e.block(n.Body)
   100  		e.loopDepth--
   101  
   102  	case ir.OSWITCH:
   103  		n := n.(*ir.SwitchStmt)
   104  
   105  		if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok {
   106  			var ks []hole
   107  			if guard.Tag != nil {
   108  				for _, cas := range n.Cases {
   109  					cv := cas.Var
   110  					k := e.dcl(cv) // type switch variables have no ODCL.
   111  					if cv.Type().HasPointers() {
   112  						ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
   113  					}
   114  				}
   115  			}
   116  			e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X)
   117  		} else {
   118  			e.discard(n.Tag)
   119  		}
   120  
   121  		for _, cas := range n.Cases {
   122  			e.discards(cas.List)
   123  			e.block(cas.Body)
   124  		}
   125  
   126  	case ir.OSELECT:
   127  		n := n.(*ir.SelectStmt)
   128  		for _, cas := range n.Cases {
   129  			e.stmt(cas.Comm)
   130  			e.block(cas.Body)
   131  		}
   132  	case ir.ORECV:
   133  		// TODO(mdempsky): Consider e.discard(n.Left).
   134  		n := n.(*ir.UnaryExpr)
   135  		e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
   136  	case ir.OSEND:
   137  		n := n.(*ir.SendStmt)
   138  		e.discard(n.Chan)
   139  		e.assignHeap(n.Value, "send", n)
   140  
   141  	case ir.OAS:
   142  		n := n.(*ir.AssignStmt)
   143  		e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
   144  	case ir.OASOP:
   145  		n := n.(*ir.AssignOpStmt)
   146  		// TODO(mdempsky): Worry about OLSH/ORSH?
   147  		e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
   148  	case ir.OAS2:
   149  		n := n.(*ir.AssignListStmt)
   150  		e.assignList(n.Lhs, n.Rhs, "assign-pair", n)
   151  
   152  	case ir.OAS2DOTTYPE: // v, ok = x.(type)
   153  		n := n.(*ir.AssignListStmt)
   154  		e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n)
   155  	case ir.OAS2MAPR: // v, ok = m[k]
   156  		n := n.(*ir.AssignListStmt)
   157  		e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n)
   158  	case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch
   159  		n := n.(*ir.AssignListStmt)
   160  		e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n)
   161  
   162  	case ir.OAS2FUNC:
   163  		n := n.(*ir.AssignListStmt)
   164  		e.stmts(n.Rhs[0].Init())
   165  		ks := e.addrs(n.Lhs)
   166  		e.call(ks, n.Rhs[0])
   167  		e.reassigned(ks, n)
   168  	case ir.ORETURN:
   169  		n := n.(*ir.ReturnStmt)
   170  		results := e.curfn.Type().Results().FieldSlice()
   171  		dsts := make([]ir.Node, len(results))
   172  		for i, res := range results {
   173  			dsts[i] = res.Nname.(*ir.Name)
   174  		}
   175  		e.assignList(dsts, n.Results, "return", n)
   176  	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OINLCALL, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
   177  		e.call(nil, n)
   178  	case ir.OGO, ir.ODEFER:
   179  		n := n.(*ir.GoDeferStmt)
   180  		e.goDeferStmt(n)
   181  
   182  	case ir.OTAILCALL:
   183  		n := n.(*ir.TailCallStmt)
   184  		e.call(nil, n.Call)
   185  	}
   186  }
   187  
   188  func (e *escape) stmts(l ir.Nodes) {
   189  	for _, n := range l {
   190  		e.stmt(n)
   191  	}
   192  }
   193  
   194  // block is like stmts, but preserves loopDepth.
   195  func (e *escape) block(l ir.Nodes) {
   196  	old := e.loopDepth
   197  	e.stmts(l)
   198  	e.loopDepth = old
   199  }
   200  
   201  func (e *escape) dcl(n *ir.Name) hole {
   202  	if n.Curfn != e.curfn || n.IsClosureVar() {
   203  		base.Fatalf("bad declaration of %v", n)
   204  	}
   205  	loc := e.oldLoc(n)
   206  	loc.loopDepth = e.loopDepth
   207  	return loc.asHole()
   208  }
   209  

View as plain text