github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/gc/order.go (about)

     1  // Copyright 2012 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 gc
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  )
    11  
    12  // Rewrite tree to use separate statements to enforce
    13  // order of evaluation. Makes walk easier, because it
    14  // can (after this runs) reorder at will within an expression.
    15  //
    16  // Rewrite x op= y into x = x op y.
    17  //
    18  // Introduce temporaries as needed by runtime routines.
    19  // For example, the map runtime routines take the map key
    20  // by reference, so make sure all map keys are addressable
    21  // by copying them to temporaries as needed.
    22  // The same is true for channel operations.
    23  //
    24  // Arrange that map index expressions only appear in direct
    25  // assignments x = m[k] or m[k] = x, never in larger expressions.
    26  //
    27  // Arrange that receive expressions only appear in direct assignments
    28  // x = <-c or as standalone statements <-c, never in larger expressions.
    29  
    30  // TODO(rsc): The temporary introduction during multiple assignments
    31  // should be moved into this file, so that the temporaries can be cleaned
    32  // and so that conversions implicit in the OAS2FUNC and OAS2RECV
    33  // nodes can be made explicit and then have their temporaries cleaned.
    34  
    35  // TODO(rsc): Goto and multilevel break/continue can jump over
    36  // inserted VARKILL annotations. Work out a way to handle these.
    37  // The current implementation is safe, in that it will execute correctly.
    38  // But it won't reuse temporaries as aggressively as it might, and
    39  // it can result in unnecessary zeroing of those variables in the function
    40  // prologue.
    41  
    42  // Order holds state during the ordering process.
    43  type Order struct {
    44  	out  []*Node // list of generated statements
    45  	temp []*Node // stack of temporary variables
    46  }
    47  
    48  // Order rewrites fn->nbody to apply the ordering constraints
    49  // described in the comment at the top of the file.
    50  func order(fn *Node) {
    51  	if Debug['W'] > 1 {
    52  		s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
    53  		dumplist(s, fn.Nbody)
    54  	}
    55  
    56  	orderblockNodes(&fn.Nbody)
    57  }
    58  
    59  // Ordertemp allocates a new temporary with the given type,
    60  // pushes it onto the temp stack, and returns it.
    61  // If clear is true, ordertemp emits code to zero the temporary.
    62  func ordertemp(t *Type, order *Order, clear bool) *Node {
    63  	var_ := temp(t)
    64  	if clear {
    65  		a := Nod(OAS, var_, nil)
    66  		a = typecheck(a, Etop)
    67  		order.out = append(order.out, a)
    68  	}
    69  
    70  	order.temp = append(order.temp, var_)
    71  	return var_
    72  }
    73  
    74  // Ordercopyexpr behaves like ordertemp but also emits
    75  // code to initialize the temporary to the value n.
    76  //
    77  // The clear argument is provided for use when the evaluation
    78  // of tmp = n turns into a function call that is passed a pointer
    79  // to the temporary as the output space. If the call blocks before
    80  // tmp has been written, the garbage collector will still treat the
    81  // temporary as live, so we must zero it before entering that call.
    82  // Today, this only happens for channel receive operations.
    83  // (The other candidate would be map access, but map access
    84  // returns a pointer to the result data instead of taking a pointer
    85  // to be filled in.)
    86  func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node {
    87  	var_ := ordertemp(t, order, clear != 0)
    88  	a := Nod(OAS, var_, n)
    89  	a = typecheck(a, Etop)
    90  	order.out = append(order.out, a)
    91  	return var_
    92  }
    93  
    94  // Ordercheapexpr returns a cheap version of n.
    95  // The definition of cheap is that n is a variable or constant.
    96  // If not, ordercheapexpr allocates a new tmp, emits tmp = n,
    97  // and then returns tmp.
    98  func ordercheapexpr(n *Node, order *Order) *Node {
    99  	if n == nil {
   100  		return nil
   101  	}
   102  	switch n.Op {
   103  	case ONAME, OLITERAL:
   104  		return n
   105  	case OLEN, OCAP:
   106  		l := ordercheapexpr(n.Left, order)
   107  		if l == n.Left {
   108  			return n
   109  		}
   110  		a := *n
   111  		a.Orig = &a
   112  		a.Left = l
   113  		return typecheck(&a, Erv)
   114  	}
   115  
   116  	return ordercopyexpr(n, n.Type, order, 0)
   117  }
   118  
   119  // Ordersafeexpr returns a safe version of n.
   120  // The definition of safe is that n can appear multiple times
   121  // without violating the semantics of the original program,
   122  // and that assigning to the safe version has the same effect
   123  // as assigning to the original n.
   124  //
   125  // The intended use is to apply to x when rewriting x += y into x = x + y.
   126  func ordersafeexpr(n *Node, order *Order) *Node {
   127  	switch n.Op {
   128  	case ONAME, OLITERAL:
   129  		return n
   130  
   131  	case ODOT, OLEN, OCAP:
   132  		l := ordersafeexpr(n.Left, order)
   133  		if l == n.Left {
   134  			return n
   135  		}
   136  		a := *n
   137  		a.Orig = &a
   138  		a.Left = l
   139  		return typecheck(&a, Erv)
   140  
   141  	case ODOTPTR, OIND:
   142  		l := ordercheapexpr(n.Left, order)
   143  		if l == n.Left {
   144  			return n
   145  		}
   146  		a := *n
   147  		a.Orig = &a
   148  		a.Left = l
   149  		return typecheck(&a, Erv)
   150  
   151  	case OINDEX, OINDEXMAP:
   152  		var l *Node
   153  		if n.Left.Type.IsArray() {
   154  			l = ordersafeexpr(n.Left, order)
   155  		} else {
   156  			l = ordercheapexpr(n.Left, order)
   157  		}
   158  		r := ordercheapexpr(n.Right, order)
   159  		if l == n.Left && r == n.Right {
   160  			return n
   161  		}
   162  		a := *n
   163  		a.Orig = &a
   164  		a.Left = l
   165  		a.Right = r
   166  		return typecheck(&a, Erv)
   167  	default:
   168  		Fatalf("ordersafeexpr %v", n.Op)
   169  		return nil // not reached
   170  	}
   171  }
   172  
   173  // Istemp reports whether n is a temporary variable.
   174  func istemp(n *Node) bool {
   175  	if n.Op != ONAME {
   176  		return false
   177  	}
   178  	return strings.HasPrefix(n.Sym.Name, "autotmp_")
   179  }
   180  
   181  // Isaddrokay reports whether it is okay to pass n's address to runtime routines.
   182  // Taking the address of a variable makes the liveness and optimization analyses
   183  // lose track of where the variable's lifetime ends. To avoid hurting the analyses
   184  // of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
   185  // because we emit explicit VARKILL instructions marking the end of those
   186  // temporaries' lifetimes.
   187  func isaddrokay(n *Node) bool {
   188  	return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || istemp(n))
   189  }
   190  
   191  // Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
   192  // If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
   193  // tmp = *np, and then sets *np to the tmp variable.
   194  func orderaddrtemp(n *Node, order *Order) *Node {
   195  	if isaddrokay(n) {
   196  		return n
   197  	}
   198  	return ordercopyexpr(n, n.Type, order, 0)
   199  }
   200  
   201  type ordermarker int
   202  
   203  // Marktemp returns the top of the temporary variable stack.
   204  func marktemp(order *Order) ordermarker {
   205  	return ordermarker(len(order.temp))
   206  }
   207  
   208  // Poptemp pops temporaries off the stack until reaching the mark,
   209  // which must have been returned by marktemp.
   210  func poptemp(mark ordermarker, order *Order) {
   211  	order.temp = order.temp[:mark]
   212  }
   213  
   214  // Cleantempnopop emits to *out VARKILL instructions for each temporary
   215  // above the mark on the temporary stack, but it does not pop them
   216  // from the stack.
   217  func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
   218  	var kill *Node
   219  
   220  	for i := len(order.temp) - 1; i >= int(mark); i-- {
   221  		n := order.temp[i]
   222  		if n.Name.Keepalive {
   223  			n.Name.Keepalive = false
   224  			n.Addrtaken = true // ensure SSA keeps the n variable
   225  			kill = Nod(OVARLIVE, n, nil)
   226  			kill = typecheck(kill, Etop)
   227  			*out = append(*out, kill)
   228  		}
   229  		kill = Nod(OVARKILL, n, nil)
   230  		kill = typecheck(kill, Etop)
   231  		*out = append(*out, kill)
   232  	}
   233  }
   234  
   235  // Cleantemp emits VARKILL instructions for each temporary above the
   236  // mark on the temporary stack and removes them from the stack.
   237  func cleantemp(top ordermarker, order *Order) {
   238  	cleantempnopop(top, order, &order.out)
   239  	poptemp(top, order)
   240  }
   241  
   242  // Orderstmtlist orders each of the statements in the list.
   243  func orderstmtlist(l Nodes, order *Order) {
   244  	for _, n := range l.Slice() {
   245  		orderstmt(n, order)
   246  	}
   247  }
   248  
   249  // Orderblock orders the block of statements l onto a new list,
   250  // and returns the ordered list.
   251  func orderblock(l Nodes) []*Node {
   252  	var order Order
   253  	mark := marktemp(&order)
   254  	orderstmtlist(l, &order)
   255  	cleantemp(mark, &order)
   256  	return order.out
   257  }
   258  
   259  // OrderblockNodes orders the block of statements in n into a new slice,
   260  // and then replaces the old slice in n with the new slice.
   261  func orderblockNodes(n *Nodes) {
   262  	var order Order
   263  	mark := marktemp(&order)
   264  	orderstmtlist(*n, &order)
   265  	cleantemp(mark, &order)
   266  	n.Set(order.out)
   267  }
   268  
   269  // Orderexprinplace orders the side effects in *np and
   270  // leaves them as the init list of the final *np.
   271  // The result of orderexprinplace MUST be assigned back to n, e.g.
   272  // 	n.Left = orderexprinplace(n.Left, outer)
   273  func orderexprinplace(n *Node, outer *Order) *Node {
   274  	var order Order
   275  	n = orderexpr(n, &order, nil)
   276  	n = addinit(n, order.out)
   277  
   278  	// insert new temporaries from order
   279  	// at head of outer list.
   280  	outer.temp = append(outer.temp, order.temp...)
   281  	return n
   282  }
   283  
   284  // Orderstmtinplace orders the side effects of the single statement *np
   285  // and replaces it with the resulting statement list.
   286  // The result of orderstmtinplace MUST be assigned back to n, e.g.
   287  // 	n.Left = orderstmtinplace(n.Left)
   288  func orderstmtinplace(n *Node) *Node {
   289  	var order Order
   290  	mark := marktemp(&order)
   291  	orderstmt(n, &order)
   292  	cleantemp(mark, &order)
   293  	return liststmt(order.out)
   294  }
   295  
   296  // Orderinit moves n's init list to order->out.
   297  func orderinit(n *Node, order *Order) {
   298  	orderstmtlist(n.Ninit, order)
   299  	n.Ninit.Set(nil)
   300  }
   301  
   302  // Ismulticall reports whether the list l is f() for a multi-value function.
   303  // Such an f() could appear as the lone argument to a multi-arg function.
   304  func ismulticall(l Nodes) bool {
   305  	// one arg only
   306  	if l.Len() != 1 {
   307  		return false
   308  	}
   309  	n := l.First()
   310  
   311  	// must be call
   312  	switch n.Op {
   313  	default:
   314  		return false
   315  
   316  	case OCALLFUNC, OCALLMETH, OCALLINTER:
   317  		break
   318  	}
   319  
   320  	// call must return multiple values
   321  	return n.Left.Type.Results().NumFields() > 1
   322  }
   323  
   324  // Copyret emits t1, t2, ... = n, where n is a function call,
   325  // and then returns the list t1, t2, ....
   326  func copyret(n *Node, order *Order) []*Node {
   327  	if !n.Type.IsFuncArgStruct() {
   328  		Fatalf("copyret %v %d", n.Type, n.Left.Type.Results().NumFields())
   329  	}
   330  
   331  	var l1 []*Node
   332  	var l2 []*Node
   333  	for _, t := range n.Type.Fields().Slice() {
   334  		tmp := temp(t.Type)
   335  		l1 = append(l1, tmp)
   336  		l2 = append(l2, tmp)
   337  	}
   338  
   339  	as := Nod(OAS2, nil, nil)
   340  	as.List.Set(l1)
   341  	as.Rlist.Set1(n)
   342  	as = typecheck(as, Etop)
   343  	orderstmt(as, order)
   344  
   345  	return l2
   346  }
   347  
   348  // Ordercallargs orders the list of call arguments *l.
   349  func ordercallargs(l *Nodes, order *Order) {
   350  	if ismulticall(*l) {
   351  		// return f() where f() is multiple values.
   352  		l.Set(copyret(l.First(), order))
   353  	} else {
   354  		orderexprlist(*l, order)
   355  	}
   356  }
   357  
   358  // Ordercall orders the call expression n.
   359  // n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
   360  func ordercall(n *Node, order *Order) {
   361  	n.Left = orderexpr(n.Left, order, nil)
   362  	n.Right = orderexpr(n.Right, order, nil) // ODDDARG temp
   363  	ordercallargs(&n.List, order)
   364  
   365  	if n.Op == OCALLFUNC {
   366  		t, it := IterFields(n.Left.Type.Params())
   367  		for i := range n.List.Slice() {
   368  			// Check for "unsafe-uintptr" tag provided by escape analysis.
   369  			// If present and the argument is really a pointer being converted
   370  			// to uintptr, arrange for the pointer to be kept alive until the call
   371  			// returns, by copying it into a temp and marking that temp
   372  			// still alive when we pop the temp stack.
   373  			if t == nil {
   374  				break
   375  			}
   376  			if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
   377  				xp := n.List.Addr(i)
   378  				for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
   379  					xp = &(*xp).Left
   380  				}
   381  				x := *xp
   382  				if x.Type.IsPtr() {
   383  					x = ordercopyexpr(x, x.Type, order, 0)
   384  					x.Name.Keepalive = true
   385  					*xp = x
   386  				}
   387  			}
   388  			next := it.Next()
   389  			if next == nil && t.Isddd && t.Note == uintptrEscapesTag {
   390  				next = t
   391  			}
   392  			t = next
   393  		}
   394  	}
   395  }
   396  
   397  // Ordermapassign appends n to order->out, introducing temporaries
   398  // to make sure that all map assignments have the form m[k] = x,
   399  // where x is addressable.
   400  // (Orderexpr has already been called on n, so we know k is addressable.)
   401  //
   402  // If n is m[k] = x where x is not addressable, the rewrite is:
   403  //	tmp = x
   404  //	m[k] = tmp
   405  //
   406  // If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
   407  //	t1 = m
   408  //	t2 = k
   409  //	...., t3, ... = x
   410  //	t1[t2] = t3
   411  //
   412  // The temporaries t1, t2 are needed in case the ... being assigned
   413  // contain m or k. They are usually unnecessary, but in the unnecessary
   414  // cases they are also typically registerizable, so not much harm done.
   415  // And this only applies to the multiple-assignment form.
   416  // We could do a more precise analysis if needed, like in walk.go.
   417  //
   418  // Ordermapassign also inserts these temporaries if needed for
   419  // calling writebarrierfat with a pointer to n->right.
   420  func ordermapassign(n *Node, order *Order) {
   421  	switch n.Op {
   422  	default:
   423  		Fatalf("ordermapassign %v", n.Op)
   424  
   425  	case OAS:
   426  		order.out = append(order.out, n)
   427  
   428  		// We call writebarrierfat only for values > 4 pointers long. See walk.go.
   429  		// TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that
   430  		// logic causes net/http's tests to become flaky; see CL 21242.
   431  		if (n.Left.Op == OINDEXMAP || (needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr))) && !isaddrokay(n.Right) {
   432  			m := n.Left
   433  			n.Left = ordertemp(m.Type, order, false)
   434  			a := Nod(OAS, m, n.Left)
   435  			a = typecheck(a, Etop)
   436  			order.out = append(order.out, a)
   437  		}
   438  
   439  	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
   440  		var post []*Node
   441  		var m *Node
   442  		var a *Node
   443  		for i1, n1 := range n.List.Slice() {
   444  			if n1.Op == OINDEXMAP {
   445  				m = n1
   446  				if !istemp(m.Left) {
   447  					m.Left = ordercopyexpr(m.Left, m.Left.Type, order, 0)
   448  				}
   449  				if !istemp(m.Right) {
   450  					m.Right = ordercopyexpr(m.Right, m.Right.Type, order, 0)
   451  				}
   452  				n.List.SetIndex(i1, ordertemp(m.Type, order, false))
   453  				a = Nod(OAS, m, n.List.Index(i1))
   454  				a = typecheck(a, Etop)
   455  				post = append(post, a)
   456  			} else if instrumenting && n.Op == OAS2FUNC && !isblank(n.List.Index(i1)) {
   457  				m = n.List.Index(i1)
   458  				t := ordertemp(m.Type, order, false)
   459  				n.List.SetIndex(i1, t)
   460  				a = Nod(OAS, m, t)
   461  				a = typecheck(a, Etop)
   462  				post = append(post, a)
   463  			}
   464  		}
   465  
   466  		order.out = append(order.out, n)
   467  		order.out = append(order.out, post...)
   468  	}
   469  }
   470  
   471  // Orderstmt orders the statement n, appending to order->out.
   472  // Temporaries created during the statement are cleaned
   473  // up using VARKILL instructions as possible.
   474  func orderstmt(n *Node, order *Order) {
   475  	if n == nil {
   476  		return
   477  	}
   478  
   479  	lno := setlineno(n)
   480  
   481  	orderinit(n, order)
   482  
   483  	switch n.Op {
   484  	default:
   485  		Fatalf("orderstmt %v", n.Op)
   486  
   487  	case OVARKILL, OVARLIVE:
   488  		order.out = append(order.out, n)
   489  
   490  	case OAS:
   491  		t := marktemp(order)
   492  		n.Left = orderexpr(n.Left, order, nil)
   493  		n.Right = orderexpr(n.Right, order, n.Left)
   494  		ordermapassign(n, order)
   495  		cleantemp(t, order)
   496  
   497  	case OAS2,
   498  		OCLOSE,
   499  		OCOPY,
   500  		OPRINT,
   501  		OPRINTN,
   502  		ORECOVER,
   503  		ORECV:
   504  		t := marktemp(order)
   505  		n.Left = orderexpr(n.Left, order, nil)
   506  		n.Right = orderexpr(n.Right, order, nil)
   507  		orderexprlist(n.List, order)
   508  		orderexprlist(n.Rlist, order)
   509  		switch n.Op {
   510  		case OAS2, OAS2DOTTYPE:
   511  			ordermapassign(n, order)
   512  		default:
   513  			order.out = append(order.out, n)
   514  		}
   515  		cleantemp(t, order)
   516  
   517  	case OASOP:
   518  		// Special: rewrite l op= r into l = l op r.
   519  		// This simplifies quite a few operations;
   520  		// most important is that it lets us separate
   521  		// out map read from map write when l is
   522  		// a map index expression.
   523  		t := marktemp(order)
   524  
   525  		n.Left = orderexpr(n.Left, order, nil)
   526  		n.Left = ordersafeexpr(n.Left, order)
   527  		tmp1 := treecopy(n.Left, 0)
   528  		if tmp1.Op == OINDEXMAP {
   529  			tmp1.Etype = 0 // now an rvalue not an lvalue
   530  		}
   531  		tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
   532  		// TODO(marvin): Fix Node.EType type union.
   533  		n.Right = Nod(Op(n.Etype), tmp1, n.Right)
   534  		n.Right = typecheck(n.Right, Erv)
   535  		n.Right = orderexpr(n.Right, order, nil)
   536  		n.Etype = 0
   537  		n.Op = OAS
   538  		ordermapassign(n, order)
   539  		cleantemp(t, order)
   540  
   541  		// Special: make sure key is addressable,
   542  	// and make sure OINDEXMAP is not copied out.
   543  	case OAS2MAPR:
   544  		t := marktemp(order)
   545  
   546  		orderexprlist(n.List, order)
   547  		r := n.Rlist.First()
   548  		r.Left = orderexpr(r.Left, order, nil)
   549  		r.Right = orderexpr(r.Right, order, nil)
   550  
   551  		// See case OINDEXMAP below.
   552  		if r.Right.Op == OARRAYBYTESTR {
   553  			r.Right.Op = OARRAYBYTESTRTMP
   554  		}
   555  		r.Right = orderaddrtemp(r.Right, order)
   556  		ordermapassign(n, order)
   557  		cleantemp(t, order)
   558  
   559  		// Special: avoid copy of func call n->rlist->n.
   560  	case OAS2FUNC:
   561  		t := marktemp(order)
   562  
   563  		orderexprlist(n.List, order)
   564  		ordercall(n.Rlist.First(), order)
   565  		ordermapassign(n, order)
   566  		cleantemp(t, order)
   567  
   568  		// Special: use temporary variables to hold result,
   569  	// so that assertI2Tetc can take address of temporary.
   570  	// No temporary for blank assignment.
   571  	case OAS2DOTTYPE:
   572  		t := marktemp(order)
   573  
   574  		orderexprlist(n.List, order)
   575  		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
   576  		if isblank(n.List.First()) {
   577  			order.out = append(order.out, n)
   578  		} else {
   579  			typ := n.Rlist.First().Type
   580  			tmp1 := ordertemp(typ, order, haspointers(typ))
   581  			order.out = append(order.out, n)
   582  			r := Nod(OAS, n.List.First(), tmp1)
   583  			r = typecheck(r, Etop)
   584  			ordermapassign(r, order)
   585  			n.List.Set([]*Node{tmp1, n.List.Second()})
   586  		}
   587  
   588  		cleantemp(t, order)
   589  
   590  		// Special: use temporary variables to hold result,
   591  	// so that chanrecv can take address of temporary.
   592  	case OAS2RECV:
   593  		t := marktemp(order)
   594  
   595  		orderexprlist(n.List, order)
   596  		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // arg to recv
   597  		ch := n.Rlist.First().Left.Type
   598  		tmp1 := ordertemp(ch.Elem(), order, haspointers(ch.Elem()))
   599  		var tmp2 *Node
   600  		if !isblank(n.List.Second()) {
   601  			tmp2 = ordertemp(n.List.Second().Type, order, false)
   602  		} else {
   603  			tmp2 = ordertemp(Types[TBOOL], order, false)
   604  		}
   605  		order.out = append(order.out, n)
   606  		r := Nod(OAS, n.List.First(), tmp1)
   607  		r = typecheck(r, Etop)
   608  		ordermapassign(r, order)
   609  		r = Nod(OAS, n.List.Second(), tmp2)
   610  		r = typecheck(r, Etop)
   611  		ordermapassign(r, order)
   612  		n.List.Set([]*Node{tmp1, tmp2})
   613  		cleantemp(t, order)
   614  
   615  		// Special: does not save n onto out.
   616  	case OBLOCK, OEMPTY:
   617  		orderstmtlist(n.List, order)
   618  
   619  		// Special: n->left is not an expression; save as is.
   620  	case OBREAK,
   621  		OCONTINUE,
   622  		ODCL,
   623  		ODCLCONST,
   624  		ODCLTYPE,
   625  		OFALL,
   626  		OXFALL,
   627  		OGOTO,
   628  		OLABEL,
   629  		ORETJMP:
   630  		order.out = append(order.out, n)
   631  
   632  		// Special: handle call arguments.
   633  	case OCALLFUNC, OCALLINTER, OCALLMETH:
   634  		t := marktemp(order)
   635  
   636  		ordercall(n, order)
   637  		order.out = append(order.out, n)
   638  		cleantemp(t, order)
   639  
   640  		// Special: order arguments to inner call but not call itself.
   641  	case ODEFER, OPROC:
   642  		t := marktemp(order)
   643  
   644  		switch n.Left.Op {
   645  		// Delete will take the address of the key.
   646  		// Copy key into new temp and do not clean it
   647  		// (it persists beyond the statement).
   648  		case ODELETE:
   649  			orderexprlist(n.Left.List, order)
   650  
   651  			t1 := marktemp(order)
   652  			np := n.Left.List.Addr(1) // map key
   653  			*np = ordercopyexpr(*np, (*np).Type, order, 0)
   654  			poptemp(t1, order)
   655  
   656  		default:
   657  			ordercall(n.Left, order)
   658  		}
   659  
   660  		order.out = append(order.out, n)
   661  		cleantemp(t, order)
   662  
   663  	case ODELETE:
   664  		t := marktemp(order)
   665  		n.List.SetIndex(0, orderexpr(n.List.Index(0), order, nil))
   666  		n.List.SetIndex(1, orderexpr(n.List.Index(1), order, nil))
   667  		n.List.SetIndex(1, orderaddrtemp(n.List.Index(1), order)) // map key
   668  		order.out = append(order.out, n)
   669  		cleantemp(t, order)
   670  
   671  		// Clean temporaries from condition evaluation at
   672  	// beginning of loop body and after for statement.
   673  	case OFOR:
   674  		t := marktemp(order)
   675  
   676  		n.Left = orderexprinplace(n.Left, order)
   677  		var l []*Node
   678  		cleantempnopop(t, order, &l)
   679  		n.Nbody.Set(append(l, n.Nbody.Slice()...))
   680  		orderblockNodes(&n.Nbody)
   681  		n.Right = orderstmtinplace(n.Right)
   682  		order.out = append(order.out, n)
   683  		cleantemp(t, order)
   684  
   685  		// Clean temporaries from condition at
   686  	// beginning of both branches.
   687  	case OIF:
   688  		t := marktemp(order)
   689  
   690  		n.Left = orderexprinplace(n.Left, order)
   691  		var l []*Node
   692  		cleantempnopop(t, order, &l)
   693  		n.Nbody.Set(append(l, n.Nbody.Slice()...))
   694  		l = nil
   695  		cleantempnopop(t, order, &l)
   696  		n.Rlist.Set(append(l, n.Rlist.Slice()...))
   697  		poptemp(t, order)
   698  		orderblockNodes(&n.Nbody)
   699  		n.Rlist.Set(orderblock(n.Rlist))
   700  		order.out = append(order.out, n)
   701  
   702  		// Special: argument will be converted to interface using convT2E
   703  	// so make sure it is an addressable temporary.
   704  	case OPANIC:
   705  		t := marktemp(order)
   706  
   707  		n.Left = orderexpr(n.Left, order, nil)
   708  		if !n.Left.Type.IsInterface() {
   709  			n.Left = orderaddrtemp(n.Left, order)
   710  		}
   711  		order.out = append(order.out, n)
   712  		cleantemp(t, order)
   713  
   714  	case ORANGE:
   715  		// n.Right is the expression being ranged over.
   716  		// order it, and then make a copy if we need one.
   717  		// We almost always do, to ensure that we don't
   718  		// see any value changes made during the loop.
   719  		// Usually the copy is cheap (e.g., array pointer,
   720  		// chan, slice, string are all tiny).
   721  		// The exception is ranging over an array value
   722  		// (not a slice, not a pointer to array),
   723  		// which must make a copy to avoid seeing updates made during
   724  		// the range body. Ranging over an array value is uncommon though.
   725  
   726  		// Mark []byte(str) range expression to reuse string backing storage.
   727  		// It is safe because the storage cannot be mutated.
   728  		if n.Right.Op == OSTRARRAYBYTE {
   729  			n.Right.Op = OSTRARRAYBYTETMP
   730  		}
   731  
   732  		t := marktemp(order)
   733  		n.Right = orderexpr(n.Right, order, nil)
   734  		switch n.Type.Etype {
   735  		default:
   736  			Fatalf("orderstmt range %v", n.Type)
   737  
   738  		case TARRAY, TSLICE:
   739  			if n.List.Len() < 2 || isblank(n.List.Second()) {
   740  				// for i := range x will only use x once, to compute len(x).
   741  				// No need to copy it.
   742  				break
   743  			}
   744  			fallthrough
   745  
   746  		case TCHAN, TSTRING:
   747  			// chan, string, slice, array ranges use value multiple times.
   748  			// make copy.
   749  			r := n.Right
   750  
   751  			if r.Type.IsString() && r.Type != Types[TSTRING] {
   752  				r = Nod(OCONV, r, nil)
   753  				r.Type = Types[TSTRING]
   754  				r = typecheck(r, Erv)
   755  			}
   756  
   757  			n.Right = ordercopyexpr(r, r.Type, order, 0)
   758  
   759  		case TMAP:
   760  			// copy the map value in case it is a map literal.
   761  			// TODO(rsc): Make tmp = literal expressions reuse tmp.
   762  			// For maps tmp is just one word so it hardly matters.
   763  			r := n.Right
   764  			n.Right = ordercopyexpr(r, r.Type, order, 0)
   765  
   766  			// n->alloc is the temp for the iterator.
   767  			prealloc[n] = ordertemp(Types[TUINT8], order, true)
   768  		}
   769  		for i := range n.List.Slice() {
   770  			n.List.SetIndex(i, orderexprinplace(n.List.Index(i), order))
   771  		}
   772  		orderblockNodes(&n.Nbody)
   773  		order.out = append(order.out, n)
   774  		cleantemp(t, order)
   775  
   776  	case ORETURN:
   777  		ordercallargs(&n.List, order)
   778  		order.out = append(order.out, n)
   779  
   780  	// Special: clean case temporaries in each block entry.
   781  	// Select must enter one of its blocks, so there is no
   782  	// need for a cleaning at the end.
   783  	// Doubly special: evaluation order for select is stricter
   784  	// than ordinary expressions. Even something like p.c
   785  	// has to be hoisted into a temporary, so that it cannot be
   786  	// reordered after the channel evaluation for a different
   787  	// case (if p were nil, then the timing of the fault would
   788  	// give this away).
   789  	case OSELECT:
   790  		t := marktemp(order)
   791  
   792  		var tmp1 *Node
   793  		var tmp2 *Node
   794  		var r *Node
   795  		for _, n2 := range n.List.Slice() {
   796  			if n2.Op != OXCASE {
   797  				Fatalf("order select case %v", n2.Op)
   798  			}
   799  			r = n2.Left
   800  			setlineno(n2)
   801  
   802  			// Append any new body prologue to ninit.
   803  			// The next loop will insert ninit into nbody.
   804  			if n2.Ninit.Len() != 0 {
   805  				Fatalf("order select ninit")
   806  			}
   807  			if r != nil {
   808  				switch r.Op {
   809  				default:
   810  					Yyerror("unknown op in select %v", r.Op)
   811  					Dump("select case", r)
   812  
   813  				// If this is case x := <-ch or case x, y := <-ch, the case has
   814  				// the ODCL nodes to declare x and y. We want to delay that
   815  				// declaration (and possible allocation) until inside the case body.
   816  				// Delete the ODCL nodes here and recreate them inside the body below.
   817  				case OSELRECV, OSELRECV2:
   818  					if r.Colas {
   819  						i := 0
   820  						if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
   821  							i++
   822  						}
   823  						if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
   824  							i++
   825  						}
   826  						if i >= r.Ninit.Len() {
   827  							r.Ninit.Set(nil)
   828  						}
   829  					}
   830  
   831  					if r.Ninit.Len() != 0 {
   832  						Yyerror("ninit on select recv")
   833  						dumplist("ninit", r.Ninit)
   834  					}
   835  
   836  					// case x = <-c
   837  					// case x, ok = <-c
   838  					// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
   839  					// r->left == N means 'case <-c'.
   840  					// c is always evaluated; x and ok are only evaluated when assigned.
   841  					r.Right.Left = orderexpr(r.Right.Left, order, nil)
   842  
   843  					if r.Right.Left.Op != ONAME {
   844  						r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0)
   845  					}
   846  
   847  					// Introduce temporary for receive and move actual copy into case body.
   848  					// avoids problems with target being addressed, as usual.
   849  					// NOTE: If we wanted to be clever, we could arrange for just one
   850  					// temporary per distinct type, sharing the temp among all receives
   851  					// with that temp. Similarly one ok bool could be shared among all
   852  					// the x,ok receives. Not worth doing until there's a clear need.
   853  					if r.Left != nil && isblank(r.Left) {
   854  						r.Left = nil
   855  					}
   856  					if r.Left != nil {
   857  						// use channel element type for temporary to avoid conversions,
   858  						// such as in case interfacevalue = <-intchan.
   859  						// the conversion happens in the OAS instead.
   860  						tmp1 = r.Left
   861  
   862  						if r.Colas {
   863  							tmp2 = Nod(ODCL, tmp1, nil)
   864  							tmp2 = typecheck(tmp2, Etop)
   865  							n2.Ninit.Append(tmp2)
   866  						}
   867  
   868  						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, haspointers(r.Right.Left.Type.Elem()))
   869  						tmp2 = Nod(OAS, tmp1, r.Left)
   870  						tmp2 = typecheck(tmp2, Etop)
   871  						n2.Ninit.Append(tmp2)
   872  					}
   873  
   874  					if r.List.Len() != 0 && isblank(r.List.First()) {
   875  						r.List.Set(nil)
   876  					}
   877  					if r.List.Len() != 0 {
   878  						tmp1 = r.List.First()
   879  						if r.Colas {
   880  							tmp2 = Nod(ODCL, tmp1, nil)
   881  							tmp2 = typecheck(tmp2, Etop)
   882  							n2.Ninit.Append(tmp2)
   883  						}
   884  
   885  						r.List.Set1(ordertemp(tmp1.Type, order, false))
   886  						tmp2 = Nod(OAS, tmp1, r.List.First())
   887  						tmp2 = typecheck(tmp2, Etop)
   888  						n2.Ninit.Append(tmp2)
   889  					}
   890  					n2.Ninit.Set(orderblock(n2.Ninit))
   891  
   892  				case OSEND:
   893  					if r.Ninit.Len() != 0 {
   894  						Yyerror("ninit on select send")
   895  						dumplist("ninit", r.Ninit)
   896  					}
   897  
   898  					// case c <- x
   899  					// r->left is c, r->right is x, both are always evaluated.
   900  					r.Left = orderexpr(r.Left, order, nil)
   901  
   902  					if !istemp(r.Left) {
   903  						r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
   904  					}
   905  					r.Right = orderexpr(r.Right, order, nil)
   906  					if !istemp(r.Right) {
   907  						r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
   908  					}
   909  				}
   910  			}
   911  
   912  			orderblockNodes(&n2.Nbody)
   913  		}
   914  		// Now that we have accumulated all the temporaries, clean them.
   915  		// Also insert any ninit queued during the previous loop.
   916  		// (The temporary cleaning must follow that ninit work.)
   917  		for _, n3 := range n.List.Slice() {
   918  			s := n3.Ninit.Slice()
   919  			cleantempnopop(t, order, &s)
   920  			n3.Nbody.Set(append(s, n3.Nbody.Slice()...))
   921  			n3.Ninit.Set(nil)
   922  		}
   923  
   924  		order.out = append(order.out, n)
   925  		poptemp(t, order)
   926  
   927  		// Special: value being sent is passed as a pointer; make it addressable.
   928  	case OSEND:
   929  		t := marktemp(order)
   930  
   931  		n.Left = orderexpr(n.Left, order, nil)
   932  		n.Right = orderexpr(n.Right, order, nil)
   933  		n.Right = orderaddrtemp(n.Right, order)
   934  		order.out = append(order.out, n)
   935  		cleantemp(t, order)
   936  
   937  		// TODO(rsc): Clean temporaries more aggressively.
   938  	// Note that because walkswitch will rewrite some of the
   939  	// switch into a binary search, this is not as easy as it looks.
   940  	// (If we ran that code here we could invoke orderstmt on
   941  	// the if-else chain instead.)
   942  	// For now just clean all the temporaries at the end.
   943  	// In practice that's fine.
   944  	case OSWITCH:
   945  		t := marktemp(order)
   946  
   947  		n.Left = orderexpr(n.Left, order, nil)
   948  		for _, n4 := range n.List.Slice() {
   949  			if n4.Op != OXCASE {
   950  				Fatalf("order switch case %v", n4.Op)
   951  			}
   952  			orderexprlistinplace(n4.List, order)
   953  			orderblockNodes(&n4.Nbody)
   954  		}
   955  
   956  		order.out = append(order.out, n)
   957  		cleantemp(t, order)
   958  	}
   959  
   960  	lineno = lno
   961  }
   962  
   963  // Orderexprlist orders the expression list l into order.
   964  func orderexprlist(l Nodes, order *Order) {
   965  	s := l.Slice()
   966  	for i := range s {
   967  		s[i] = orderexpr(s[i], order, nil)
   968  	}
   969  }
   970  
   971  // Orderexprlist orders the expression list l but saves
   972  // the side effects on the individual expression ninit lists.
   973  func orderexprlistinplace(l Nodes, order *Order) {
   974  	s := l.Slice()
   975  	for i := range s {
   976  		s[i] = orderexprinplace(s[i], order)
   977  	}
   978  }
   979  
   980  // prealloc[x] records the allocation to use for x.
   981  var prealloc = map[*Node]*Node{}
   982  
   983  // Orderexpr orders a single expression, appending side
   984  // effects to order->out as needed.
   985  // If this is part of an assignment lhs = *np, lhs is given.
   986  // Otherwise lhs == nil. (When lhs != nil it may be possible
   987  // to avoid copying the result of the expression to a temporary.)
   988  // The result of orderexpr MUST be assigned back to n, e.g.
   989  // 	n.Left = orderexpr(n.Left, order, lhs)
   990  func orderexpr(n *Node, order *Order, lhs *Node) *Node {
   991  	if n == nil {
   992  		return n
   993  	}
   994  
   995  	lno := setlineno(n)
   996  	orderinit(n, order)
   997  
   998  	switch n.Op {
   999  	default:
  1000  		n.Left = orderexpr(n.Left, order, nil)
  1001  		n.Right = orderexpr(n.Right, order, nil)
  1002  		orderexprlist(n.List, order)
  1003  		orderexprlist(n.Rlist, order)
  1004  
  1005  		// Addition of strings turns into a function call.
  1006  	// Allocate a temporary to hold the strings.
  1007  	// Fewer than 5 strings use direct runtime helpers.
  1008  	case OADDSTR:
  1009  		orderexprlist(n.List, order)
  1010  
  1011  		if n.List.Len() > 5 {
  1012  			t := typArray(Types[TSTRING], int64(n.List.Len()))
  1013  			prealloc[n] = ordertemp(t, order, false)
  1014  		}
  1015  
  1016  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1017  		// buffer during conversion. String concatenation does not
  1018  		// memorize the strings for later use, so it is safe.
  1019  		// However, we can do it only if there is at least one non-empty string literal.
  1020  		// Otherwise if all other arguments are empty strings,
  1021  		// concatstrings will return the reference to the temp string
  1022  		// to the caller.
  1023  		hasbyte := false
  1024  
  1025  		haslit := false
  1026  		for _, n1 := range n.List.Slice() {
  1027  			hasbyte = hasbyte || n1.Op == OARRAYBYTESTR
  1028  			haslit = haslit || n1.Op == OLITERAL && len(n1.Val().U.(string)) != 0
  1029  		}
  1030  
  1031  		if haslit && hasbyte {
  1032  			for _, n2 := range n.List.Slice() {
  1033  				if n2.Op == OARRAYBYTESTR {
  1034  					n2.Op = OARRAYBYTESTRTMP
  1035  				}
  1036  			}
  1037  		}
  1038  
  1039  	case OCMPSTR:
  1040  		n.Left = orderexpr(n.Left, order, nil)
  1041  		n.Right = orderexpr(n.Right, order, nil)
  1042  
  1043  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1044  		// buffer during conversion. String comparison does not
  1045  		// memorize the strings for later use, so it is safe.
  1046  		if n.Left.Op == OARRAYBYTESTR {
  1047  			n.Left.Op = OARRAYBYTESTRTMP
  1048  		}
  1049  		if n.Right.Op == OARRAYBYTESTR {
  1050  			n.Right.Op = OARRAYBYTESTRTMP
  1051  		}
  1052  
  1053  		// key must be addressable
  1054  	case OINDEXMAP:
  1055  		n.Left = orderexpr(n.Left, order, nil)
  1056  
  1057  		n.Right = orderexpr(n.Right, order, nil)
  1058  
  1059  		// For x = m[string(k)] where k is []byte, the allocation of
  1060  		// backing bytes for the string can be avoided by reusing
  1061  		// the []byte backing array. This is a special case that it
  1062  		// would be nice to handle more generally, but because
  1063  		// there are no []byte-keyed maps, this specific case comes
  1064  		// up in important cases in practice. See issue 3512.
  1065  		// Nothing can change the []byte we are not copying before
  1066  		// the map index, because the map access is going to
  1067  		// be forced to happen immediately following this
  1068  		// conversion (by the ordercopyexpr a few lines below).
  1069  		if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR {
  1070  			n.Right.Op = OARRAYBYTESTRTMP
  1071  		}
  1072  
  1073  		n.Right = orderaddrtemp(n.Right, order)
  1074  		if n.Etype == 0 {
  1075  			// use of value (not being assigned);
  1076  			// make copy in temporary.
  1077  			n = ordercopyexpr(n, n.Type, order, 0)
  1078  		}
  1079  
  1080  		// concrete type (not interface) argument must be addressable
  1081  	// temporary to pass to runtime.
  1082  	case OCONVIFACE:
  1083  		n.Left = orderexpr(n.Left, order, nil)
  1084  
  1085  		if !n.Left.Type.IsInterface() {
  1086  			n.Left = orderaddrtemp(n.Left, order)
  1087  		}
  1088  
  1089  	case OCONVNOP:
  1090  		if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
  1091  			// When reordering unsafe.Pointer(f()) into a separate
  1092  			// statement, the conversion and function call must stay
  1093  			// together. See golang.org/issue/15329.
  1094  			orderinit(n.Left, order)
  1095  			ordercall(n.Left, order)
  1096  			if lhs == nil || lhs.Op != ONAME || instrumenting {
  1097  				n = ordercopyexpr(n, n.Type, order, 0)
  1098  			}
  1099  		} else {
  1100  			n.Left = orderexpr(n.Left, order, nil)
  1101  		}
  1102  
  1103  	case OANDAND, OOROR:
  1104  		mark := marktemp(order)
  1105  		n.Left = orderexpr(n.Left, order, nil)
  1106  
  1107  		// Clean temporaries from first branch at beginning of second.
  1108  		// Leave them on the stack so that they can be killed in the outer
  1109  		// context in case the short circuit is taken.
  1110  		var s []*Node
  1111  
  1112  		cleantempnopop(mark, order, &s)
  1113  		n.Right.Ninit.Set(append(s, n.Right.Ninit.Slice()...))
  1114  		n.Right = orderexprinplace(n.Right, order)
  1115  
  1116  	case OCALLFUNC,
  1117  		OCALLINTER,
  1118  		OCALLMETH,
  1119  		OCAP,
  1120  		OCOMPLEX,
  1121  		OCOPY,
  1122  		OIMAG,
  1123  		OLEN,
  1124  		OMAKECHAN,
  1125  		OMAKEMAP,
  1126  		OMAKESLICE,
  1127  		ONEW,
  1128  		OREAL,
  1129  		ORECOVER,
  1130  		OSTRARRAYBYTE,
  1131  		OSTRARRAYBYTETMP,
  1132  		OSTRARRAYRUNE:
  1133  		ordercall(n, order)
  1134  		if lhs == nil || lhs.Op != ONAME || instrumenting {
  1135  			n = ordercopyexpr(n, n.Type, order, 0)
  1136  		}
  1137  
  1138  	case OAPPEND:
  1139  		ordercallargs(&n.List, order)
  1140  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
  1141  			n = ordercopyexpr(n, n.Type, order, 0)
  1142  		}
  1143  
  1144  	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
  1145  		n.Left = orderexpr(n.Left, order, nil)
  1146  		low, high, max := n.SliceBounds()
  1147  		low = orderexpr(low, order, nil)
  1148  		low = ordercheapexpr(low, order)
  1149  		high = orderexpr(high, order, nil)
  1150  		high = ordercheapexpr(high, order)
  1151  		max = orderexpr(max, order, nil)
  1152  		max = ordercheapexpr(max, order)
  1153  		n.SetSliceBounds(low, high, max)
  1154  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
  1155  			n = ordercopyexpr(n, n.Type, order, 0)
  1156  		}
  1157  
  1158  	case OCLOSURE:
  1159  		if n.Noescape && n.Func.Cvars.Len() > 0 {
  1160  			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
  1161  		}
  1162  
  1163  	case OARRAYLIT, OCALLPART:
  1164  		n.Left = orderexpr(n.Left, order, nil)
  1165  		n.Right = orderexpr(n.Right, order, nil)
  1166  		orderexprlist(n.List, order)
  1167  		orderexprlist(n.Rlist, order)
  1168  		if n.Noescape {
  1169  			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
  1170  		}
  1171  
  1172  	case ODDDARG:
  1173  		if n.Noescape {
  1174  			// The ddd argument does not live beyond the call it is created for.
  1175  			// Allocate a temporary that will be cleaned up when this statement
  1176  			// completes. We could be more aggressive and try to arrange for it
  1177  			// to be cleaned up when the call completes.
  1178  			prealloc[n] = ordertemp(n.Type.Elem(), order, false)
  1179  		}
  1180  
  1181  	case ODOTTYPE, ODOTTYPE2:
  1182  		n.Left = orderexpr(n.Left, order, nil)
  1183  		// TODO(rsc): The Isfat is for consistency with componentgen and walkexpr.
  1184  		// It needs to be removed in all three places.
  1185  		// That would allow inlining x.(struct{*int}) the same as x.(*int).
  1186  		if !isdirectiface(n.Type) || Isfat(n.Type) || instrumenting {
  1187  			n = ordercopyexpr(n, n.Type, order, 1)
  1188  		}
  1189  
  1190  	case ORECV:
  1191  		n.Left = orderexpr(n.Left, order, nil)
  1192  		n = ordercopyexpr(n, n.Type, order, 1)
  1193  
  1194  	case OEQ, ONE:
  1195  		n.Left = orderexpr(n.Left, order, nil)
  1196  		n.Right = orderexpr(n.Right, order, nil)
  1197  		t := n.Left.Type
  1198  		if t.IsStruct() || t.IsArray() {
  1199  			// for complex comparisons, we need both args to be
  1200  			// addressable so we can pass them to the runtime.
  1201  			n.Left = orderaddrtemp(n.Left, order)
  1202  			n.Right = orderaddrtemp(n.Right, order)
  1203  		}
  1204  	}
  1205  
  1206  	lineno = lno
  1207  	return n
  1208  }