github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/range.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  package gc
     6  
     7  import (
     8  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     9  	"github.com/gagliardetto/golang-go/cmd/internal/sys"
    10  	"unicode/utf8"
    11  )
    12  
    13  // range
    14  func typecheckrange(n *Node) {
    15  	// Typechecking order is important here:
    16  	// 0. first typecheck range expression (slice/map/chan),
    17  	//	it is evaluated only once and so logically it is not part of the loop.
    18  	// 1. typecheck produced values,
    19  	//	this part can declare new vars and so it must be typechecked before body,
    20  	//	because body can contain a closure that captures the vars.
    21  	// 2. decldepth++ to denote loop body.
    22  	// 3. typecheck body.
    23  	// 4. decldepth--.
    24  	typecheckrangeExpr(n)
    25  
    26  	// second half of dance, the first half being typecheckrangeExpr
    27  	n.SetTypecheck(1)
    28  	ls := n.List.Slice()
    29  	for i1, n1 := range ls {
    30  		if n1.Typecheck() == 0 {
    31  			ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
    32  		}
    33  	}
    34  
    35  	decldepth++
    36  	typecheckslice(n.Nbody.Slice(), ctxStmt)
    37  	decldepth--
    38  }
    39  
    40  func typecheckrangeExpr(n *Node) {
    41  	n.Right = typecheck(n.Right, ctxExpr)
    42  
    43  	t := n.Right.Type
    44  	if t == nil {
    45  		return
    46  	}
    47  	// delicate little dance.  see typecheckas2
    48  	ls := n.List.Slice()
    49  	for i1, n1 := range ls {
    50  		if n1.Name == nil || n1.Name.Defn != n {
    51  			ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
    52  		}
    53  	}
    54  
    55  	if t.IsPtr() && t.Elem().IsArray() {
    56  		t = t.Elem()
    57  	}
    58  	n.Type = t
    59  
    60  	var t1, t2 *types.Type
    61  	toomany := false
    62  	switch t.Etype {
    63  	default:
    64  		yyerrorl(n.Pos, "cannot range over %L", n.Right)
    65  		return
    66  
    67  	case TARRAY, TSLICE:
    68  		t1 = types.Types[TINT]
    69  		t2 = t.Elem()
    70  
    71  	case TMAP:
    72  		t1 = t.Key()
    73  		t2 = t.Elem()
    74  
    75  	case TCHAN:
    76  		if !t.ChanDir().CanRecv() {
    77  			yyerrorl(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
    78  			return
    79  		}
    80  
    81  		t1 = t.Elem()
    82  		t2 = nil
    83  		if n.List.Len() == 2 {
    84  			toomany = true
    85  		}
    86  
    87  	case TSTRING:
    88  		t1 = types.Types[TINT]
    89  		t2 = types.Runetype
    90  	}
    91  
    92  	if n.List.Len() > 2 || toomany {
    93  		yyerrorl(n.Pos, "too many variables in range")
    94  	}
    95  
    96  	var v1, v2 *Node
    97  	if n.List.Len() != 0 {
    98  		v1 = n.List.First()
    99  	}
   100  	if n.List.Len() > 1 {
   101  		v2 = n.List.Second()
   102  	}
   103  
   104  	// this is not only an optimization but also a requirement in the spec.
   105  	// "if the second iteration variable is the blank identifier, the range
   106  	// clause is equivalent to the same clause with only the first variable
   107  	// present."
   108  	if v2.isBlank() {
   109  		if v1 != nil {
   110  			n.List.Set1(v1)
   111  		}
   112  		v2 = nil
   113  	}
   114  
   115  	var why string
   116  	if v1 != nil {
   117  		if v1.Name != nil && v1.Name.Defn == n {
   118  			v1.Type = t1
   119  		} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
   120  			yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
   121  		}
   122  		checkassign(n, v1)
   123  	}
   124  
   125  	if v2 != nil {
   126  		if v2.Name != nil && v2.Name.Defn == n {
   127  			v2.Type = t2
   128  		} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
   129  			yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
   130  		}
   131  		checkassign(n, v2)
   132  	}
   133  }
   134  
   135  func cheapComputableIndex(width int64) bool {
   136  	switch thearch.LinkArch.Family {
   137  	// MIPS does not have R+R addressing
   138  	// Arm64 may lack ability to generate this code in our assembler,
   139  	// but the architecture supports it.
   140  	case sys.PPC64, sys.S390X:
   141  		return width == 1
   142  	case sys.AMD64, sys.I386, sys.ARM64, sys.ARM:
   143  		switch width {
   144  		case 1, 2, 4, 8:
   145  			return true
   146  		}
   147  	}
   148  	return false
   149  }
   150  
   151  // walkrange transforms various forms of ORANGE into
   152  // simpler forms.  The result must be assigned back to n.
   153  // Node n may also be modified in place, and may also be
   154  // the returned node.
   155  func walkrange(n *Node) *Node {
   156  	if isMapClear(n) {
   157  		m := n.Right
   158  		lno := setlineno(m)
   159  		n = mapClear(m)
   160  		lineno = lno
   161  		return n
   162  	}
   163  
   164  	// variable name conventions:
   165  	//	ohv1, hv1, hv2: hidden (old) val 1, 2
   166  	//	ha, hit: hidden aggregate, iterator
   167  	//	hn, hp: hidden len, pointer
   168  	//	hb: hidden bool
   169  	//	a, v1, v2: not hidden aggregate, val 1, 2
   170  
   171  	t := n.Type
   172  
   173  	a := n.Right
   174  	lno := setlineno(a)
   175  	n.Right = nil
   176  
   177  	var v1, v2 *Node
   178  	l := n.List.Len()
   179  	if l > 0 {
   180  		v1 = n.List.First()
   181  	}
   182  
   183  	if l > 1 {
   184  		v2 = n.List.Second()
   185  	}
   186  
   187  	if v2.isBlank() {
   188  		v2 = nil
   189  	}
   190  
   191  	if v1.isBlank() && v2 == nil {
   192  		v1 = nil
   193  	}
   194  
   195  	if v1 == nil && v2 != nil {
   196  		Fatalf("walkrange: v2 != nil while v1 == nil")
   197  	}
   198  
   199  	// n.List has no meaning anymore, clear it
   200  	// to avoid erroneous processing by racewalk.
   201  	n.List.Set(nil)
   202  
   203  	var ifGuard *Node
   204  
   205  	translatedLoopOp := OFOR
   206  
   207  	var body []*Node
   208  	var init []*Node
   209  	switch t.Etype {
   210  	default:
   211  		Fatalf("walkrange")
   212  
   213  	case TARRAY, TSLICE:
   214  		if arrayClear(n, v1, v2, a) {
   215  			lineno = lno
   216  			return n
   217  		}
   218  
   219  		// order.stmt arranged for a copy of the array/slice variable if needed.
   220  		ha := a
   221  
   222  		hv1 := temp(types.Types[TINT])
   223  		hn := temp(types.Types[TINT])
   224  
   225  		init = append(init, nod(OAS, hv1, nil))
   226  		init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
   227  
   228  		n.Left = nod(OLT, hv1, hn)
   229  		n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
   230  
   231  		// for range ha { body }
   232  		if v1 == nil {
   233  			break
   234  		}
   235  
   236  		// for v1 := range ha { body }
   237  		if v2 == nil {
   238  			body = []*Node{nod(OAS, v1, hv1)}
   239  			break
   240  		}
   241  
   242  		// for v1, v2 := range ha { body }
   243  		if cheapComputableIndex(n.Type.Elem().Width) {
   244  			// v1, v2 = hv1, ha[hv1]
   245  			tmp := nod(OINDEX, ha, hv1)
   246  			tmp.SetBounded(true)
   247  			// Use OAS2 to correctly handle assignments
   248  			// of the form "v1, a[v1] := range".
   249  			a := nod(OAS2, nil, nil)
   250  			a.List.Set2(v1, v2)
   251  			a.Rlist.Set2(hv1, tmp)
   252  			body = []*Node{a}
   253  			break
   254  		}
   255  
   256  		// TODO(austin): OFORUNTIL is a strange beast, but is
   257  		// necessary for expressing the control flow we need
   258  		// while also making "break" and "continue" work. It
   259  		// would be nice to just lower ORANGE during SSA, but
   260  		// racewalk needs to see many of the operations
   261  		// involved in ORANGE's implementation. If racewalk
   262  		// moves into SSA, consider moving ORANGE into SSA and
   263  		// eliminating OFORUNTIL.
   264  
   265  		// TODO(austin): OFORUNTIL inhibits bounds-check
   266  		// elimination on the index variable (see #20711).
   267  		// Enhance the prove pass to understand this.
   268  		ifGuard = nod(OIF, nil, nil)
   269  		ifGuard.Left = nod(OLT, hv1, hn)
   270  		translatedLoopOp = OFORUNTIL
   271  
   272  		hp := temp(types.NewPtr(n.Type.Elem()))
   273  		tmp := nod(OINDEX, ha, nodintconst(0))
   274  		tmp.SetBounded(true)
   275  		init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
   276  
   277  		// Use OAS2 to correctly handle assignments
   278  		// of the form "v1, a[v1] := range".
   279  		a := nod(OAS2, nil, nil)
   280  		a.List.Set2(v1, v2)
   281  		a.Rlist.Set2(hv1, nod(ODEREF, hp, nil))
   282  		body = append(body, a)
   283  
   284  		// Advance pointer as part of the late increment.
   285  		//
   286  		// This runs *after* the condition check, so we know
   287  		// advancing the pointer is safe and won't go past the
   288  		// end of the allocation.
   289  		a = nod(OAS, hp, addptr(hp, t.Elem().Width))
   290  		a = typecheck(a, ctxStmt)
   291  		n.List.Set1(a)
   292  
   293  	case TMAP:
   294  		// order.stmt allocated the iterator for us.
   295  		// we only use a once, so no copy needed.
   296  		ha := a
   297  
   298  		hit := prealloc[n]
   299  		th := hit.Type
   300  		n.Left = nil
   301  		keysym := th.Field(0).Sym  // depends on layout of iterator struct.  See reflect.go:hiter
   302  		elemsym := th.Field(1).Sym // ditto
   303  
   304  		fn := syslook("mapiterinit")
   305  
   306  		fn = substArgTypes(fn, t.Key(), t.Elem(), th)
   307  		init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
   308  		n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
   309  
   310  		fn = syslook("mapiternext")
   311  		fn = substArgTypes(fn, th)
   312  		n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
   313  
   314  		key := nodSym(ODOT, hit, keysym)
   315  		key = nod(ODEREF, key, nil)
   316  		if v1 == nil {
   317  			body = nil
   318  		} else if v2 == nil {
   319  			body = []*Node{nod(OAS, v1, key)}
   320  		} else {
   321  			elem := nodSym(ODOT, hit, elemsym)
   322  			elem = nod(ODEREF, elem, nil)
   323  			a := nod(OAS2, nil, nil)
   324  			a.List.Set2(v1, v2)
   325  			a.Rlist.Set2(key, elem)
   326  			body = []*Node{a}
   327  		}
   328  
   329  	case TCHAN:
   330  		// order.stmt arranged for a copy of the channel variable.
   331  		ha := a
   332  
   333  		n.Left = nil
   334  
   335  		hv1 := temp(t.Elem())
   336  		hv1.SetTypecheck(1)
   337  		if types.Haspointers(t.Elem()) {
   338  			init = append(init, nod(OAS, hv1, nil))
   339  		}
   340  		hb := temp(types.Types[TBOOL])
   341  
   342  		n.Left = nod(ONE, hb, nodbool(false))
   343  		a := nod(OAS2RECV, nil, nil)
   344  		a.SetTypecheck(1)
   345  		a.List.Set2(hv1, hb)
   346  		a.Right = nod(ORECV, ha, nil)
   347  		n.Left.Ninit.Set1(a)
   348  		if v1 == nil {
   349  			body = nil
   350  		} else {
   351  			body = []*Node{nod(OAS, v1, hv1)}
   352  		}
   353  		// Zero hv1. This prevents hv1 from being the sole, inaccessible
   354  		// reference to an otherwise GC-able value during the next channel receive.
   355  		// See issue 15281.
   356  		body = append(body, nod(OAS, hv1, nil))
   357  
   358  	case TSTRING:
   359  		// Transform string range statements like "for v1, v2 = range a" into
   360  		//
   361  		// ha := a
   362  		// for hv1 := 0; hv1 < len(ha); {
   363  		//   hv1t := hv1
   364  		//   hv2 := rune(ha[hv1])
   365  		//   if hv2 < utf8.RuneSelf {
   366  		//      hv1++
   367  		//   } else {
   368  		//      hv2, hv1 = decoderune(ha, hv1)
   369  		//   }
   370  		//   v1, v2 = hv1t, hv2
   371  		//   // original body
   372  		// }
   373  
   374  		// order.stmt arranged for a copy of the string variable.
   375  		ha := a
   376  
   377  		hv1 := temp(types.Types[TINT])
   378  		hv1t := temp(types.Types[TINT])
   379  		hv2 := temp(types.Runetype)
   380  
   381  		// hv1 := 0
   382  		init = append(init, nod(OAS, hv1, nil))
   383  
   384  		// hv1 < len(ha)
   385  		n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
   386  
   387  		if v1 != nil {
   388  			// hv1t = hv1
   389  			body = append(body, nod(OAS, hv1t, hv1))
   390  		}
   391  
   392  		// hv2 := rune(ha[hv1])
   393  		nind := nod(OINDEX, ha, hv1)
   394  		nind.SetBounded(true)
   395  		body = append(body, nod(OAS, hv2, conv(nind, types.Runetype)))
   396  
   397  		// if hv2 < utf8.RuneSelf
   398  		nif := nod(OIF, nil, nil)
   399  		nif.Left = nod(OLT, hv2, nodintconst(utf8.RuneSelf))
   400  
   401  		// hv1++
   402  		nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
   403  
   404  		// } else {
   405  		eif := nod(OAS2, nil, nil)
   406  		nif.Rlist.Set1(eif)
   407  
   408  		// hv2, hv1 = decoderune(ha, hv1)
   409  		eif.List.Set2(hv2, hv1)
   410  		fn := syslook("decoderune")
   411  		eif.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
   412  
   413  		body = append(body, nif)
   414  
   415  		if v1 != nil {
   416  			if v2 != nil {
   417  				// v1, v2 = hv1t, hv2
   418  				a := nod(OAS2, nil, nil)
   419  				a.List.Set2(v1, v2)
   420  				a.Rlist.Set2(hv1t, hv2)
   421  				body = append(body, a)
   422  			} else {
   423  				// v1 = hv1t
   424  				body = append(body, nod(OAS, v1, hv1t))
   425  			}
   426  		}
   427  	}
   428  
   429  	n.Op = translatedLoopOp
   430  	typecheckslice(init, ctxStmt)
   431  
   432  	if ifGuard != nil {
   433  		ifGuard.Ninit.Append(init...)
   434  		ifGuard = typecheck(ifGuard, ctxStmt)
   435  	} else {
   436  		n.Ninit.Append(init...)
   437  	}
   438  
   439  	typecheckslice(n.Left.Ninit.Slice(), ctxStmt)
   440  
   441  	n.Left = typecheck(n.Left, ctxExpr)
   442  	n.Left = defaultlit(n.Left, nil)
   443  	n.Right = typecheck(n.Right, ctxStmt)
   444  	typecheckslice(body, ctxStmt)
   445  	n.Nbody.Prepend(body...)
   446  
   447  	if ifGuard != nil {
   448  		ifGuard.Nbody.Set1(n)
   449  		n = ifGuard
   450  	}
   451  
   452  	n = walkstmt(n)
   453  
   454  	lineno = lno
   455  	return n
   456  }
   457  
   458  // isMapClear checks if n is of the form:
   459  //
   460  // for k := range m {
   461  //   delete(m, k)
   462  // }
   463  //
   464  // where == for keys of map m is reflexive.
   465  func isMapClear(n *Node) bool {
   466  	if Debug['N'] != 0 || instrumenting {
   467  		return false
   468  	}
   469  
   470  	if n.Op != ORANGE || n.Type.Etype != TMAP || n.List.Len() != 1 {
   471  		return false
   472  	}
   473  
   474  	k := n.List.First()
   475  	if k == nil || k.isBlank() {
   476  		return false
   477  	}
   478  
   479  	// Require k to be a new variable name.
   480  	if k.Name == nil || k.Name.Defn != n {
   481  		return false
   482  	}
   483  
   484  	if n.Nbody.Len() != 1 {
   485  		return false
   486  	}
   487  
   488  	stmt := n.Nbody.First() // only stmt in body
   489  	if stmt == nil || stmt.Op != ODELETE {
   490  		return false
   491  	}
   492  
   493  	m := n.Right
   494  	if !samesafeexpr(stmt.List.First(), m) || !samesafeexpr(stmt.List.Second(), k) {
   495  		return false
   496  	}
   497  
   498  	// Keys where equality is not reflexive can not be deleted from maps.
   499  	if !isreflexive(m.Type.Key()) {
   500  		return false
   501  	}
   502  
   503  	return true
   504  }
   505  
   506  // mapClear constructs a call to runtime.mapclear for the map m.
   507  func mapClear(m *Node) *Node {
   508  	t := m.Type
   509  
   510  	// instantiate mapclear(typ *type, hmap map[any]any)
   511  	fn := syslook("mapclear")
   512  	fn = substArgTypes(fn, t.Key(), t.Elem())
   513  	n := mkcall1(fn, nil, nil, typename(t), m)
   514  
   515  	n = typecheck(n, ctxStmt)
   516  	n = walkstmt(n)
   517  
   518  	return n
   519  }
   520  
   521  // Lower n into runtime·memclr if possible, for
   522  // fast zeroing of slices and arrays (issue 5373).
   523  // Look for instances of
   524  //
   525  // for i := range a {
   526  // 	a[i] = zero
   527  // }
   528  //
   529  // in which the evaluation of a is side-effect-free.
   530  //
   531  // Parameters are as in walkrange: "for v1, v2 = range a".
   532  func arrayClear(n, v1, v2, a *Node) bool {
   533  	if Debug['N'] != 0 || instrumenting {
   534  		return false
   535  	}
   536  
   537  	if v1 == nil || v2 != nil {
   538  		return false
   539  	}
   540  
   541  	if n.Nbody.Len() != 1 || n.Nbody.First() == nil {
   542  		return false
   543  	}
   544  
   545  	stmt := n.Nbody.First() // only stmt in body
   546  	if stmt.Op != OAS || stmt.Left.Op != OINDEX {
   547  		return false
   548  	}
   549  
   550  	if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
   551  		return false
   552  	}
   553  
   554  	elemsize := n.Type.Elem().Width
   555  	if elemsize <= 0 || !isZero(stmt.Right) {
   556  		return false
   557  	}
   558  
   559  	// Convert to
   560  	// if len(a) != 0 {
   561  	// 	hp = &a[0]
   562  	// 	hn = len(a)*sizeof(elem(a))
   563  	// 	memclr{NoHeap,Has}Pointers(hp, hn)
   564  	// 	i = len(a) - 1
   565  	// }
   566  	n.Op = OIF
   567  
   568  	n.Nbody.Set(nil)
   569  	n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
   570  
   571  	// hp = &a[0]
   572  	hp := temp(types.Types[TUNSAFEPTR])
   573  
   574  	tmp := nod(OINDEX, a, nodintconst(0))
   575  	tmp.SetBounded(true)
   576  	tmp = nod(OADDR, tmp, nil)
   577  	tmp = convnop(tmp, types.Types[TUNSAFEPTR])
   578  	n.Nbody.Append(nod(OAS, hp, tmp))
   579  
   580  	// hn = len(a) * sizeof(elem(a))
   581  	hn := temp(types.Types[TUINTPTR])
   582  
   583  	tmp = nod(OLEN, a, nil)
   584  	tmp = nod(OMUL, tmp, nodintconst(elemsize))
   585  	tmp = conv(tmp, types.Types[TUINTPTR])
   586  	n.Nbody.Append(nod(OAS, hn, tmp))
   587  
   588  	var fn *Node
   589  	if a.Type.Elem().HasHeapPointer() {
   590  		// memclrHasPointers(hp, hn)
   591  		Curfn.Func.setWBPos(stmt.Pos)
   592  		fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
   593  	} else {
   594  		// memclrNoHeapPointers(hp, hn)
   595  		fn = mkcall("memclrNoHeapPointers", nil, nil, hp, hn)
   596  	}
   597  
   598  	n.Nbody.Append(fn)
   599  
   600  	// i = len(a) - 1
   601  	v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, nil), nodintconst(1)))
   602  
   603  	n.Nbody.Append(v1)
   604  
   605  	n.Left = typecheck(n.Left, ctxExpr)
   606  	n.Left = defaultlit(n.Left, nil)
   607  	typecheckslice(n.Nbody.Slice(), ctxStmt)
   608  	n = walkstmt(n)
   609  	return true
   610  }
   611  
   612  // addptr returns (*T)(uintptr(p) + n).
   613  func addptr(p *Node, n int64) *Node {
   614  	t := p.Type
   615  
   616  	p = nod(OCONVNOP, p, nil)
   617  	p.Type = types.Types[TUINTPTR]
   618  
   619  	p = nod(OADD, p, nodintconst(n))
   620  
   621  	p = nod(OCONVNOP, p, nil)
   622  	p.Type = t
   623  
   624  	return p
   625  }