Home | History | Annotate | Download | only in gc
      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 "unicode/utf8"
      8 
      9 // range
     10 func typecheckrange(n *Node) {
     11 	var toomany int
     12 	var why string
     13 	var t1 *Type
     14 	var t2 *Type
     15 	var v1 *Node
     16 	var v2 *Node
     17 	var ls []*Node
     18 
     19 	// Typechecking order is important here:
     20 	// 0. first typecheck range expression (slice/map/chan),
     21 	//	it is evaluated only once and so logically it is not part of the loop.
     22 	// 1. typcheck produced values,
     23 	//	this part can declare new vars and so it must be typechecked before body,
     24 	//	because body can contain a closure that captures the vars.
     25 	// 2. decldepth++ to denote loop body.
     26 	// 3. typecheck body.
     27 	// 4. decldepth--.
     28 
     29 	n.Right = typecheck(n.Right, Erv)
     30 
     31 	t := n.Right.Type
     32 	if t == nil {
     33 		goto out
     34 	}
     35 	// delicate little dance.  see typecheckas2
     36 	ls = n.List.Slice()
     37 	for i1, n1 := range ls {
     38 		if n1.Name == nil || n1.Name.Defn != n {
     39 			ls[i1] = typecheck(ls[i1], Erv|Easgn)
     40 		}
     41 	}
     42 
     43 	if t.IsPtr() && t.Elem().IsArray() {
     44 		t = t.Elem()
     45 	}
     46 	n.Type = t
     47 
     48 	toomany = 0
     49 	switch t.Etype {
     50 	default:
     51 		yyerror("cannot range over %L", n.Right)
     52 		goto out
     53 
     54 	case TARRAY, TSLICE:
     55 		t1 = Types[TINT]
     56 		t2 = t.Elem()
     57 
     58 	case TMAP:
     59 		t1 = t.Key()
     60 		t2 = t.Val()
     61 
     62 	case TCHAN:
     63 		if !t.ChanDir().CanRecv() {
     64 			yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
     65 			goto out
     66 		}
     67 
     68 		t1 = t.Elem()
     69 		t2 = nil
     70 		if n.List.Len() == 2 {
     71 			toomany = 1
     72 		}
     73 
     74 	case TSTRING:
     75 		t1 = Types[TINT]
     76 		t2 = runetype
     77 	}
     78 
     79 	if n.List.Len() > 2 || toomany != 0 {
     80 		yyerror("too many variables in range")
     81 	}
     82 
     83 	v1 = nil
     84 	if n.List.Len() != 0 {
     85 		v1 = n.List.First()
     86 	}
     87 	v2 = nil
     88 	if n.List.Len() > 1 {
     89 		v2 = n.List.Second()
     90 	}
     91 
     92 	// this is not only a optimization but also a requirement in the spec.
     93 	// "if the second iteration variable is the blank identifier, the range
     94 	// clause is equivalent to the same clause with only the first variable
     95 	// present."
     96 	if isblank(v2) {
     97 		if v1 != nil {
     98 			n.List.Set1(v1)
     99 		}
    100 		v2 = nil
    101 	}
    102 
    103 	if v1 != nil {
    104 		if v1.Name != nil && v1.Name.Defn == n {
    105 			v1.Type = t1
    106 		} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
    107 			yyerror("cannot assign type %v to %L in range%s", t1, v1, why)
    108 		}
    109 		checkassign(n, v1)
    110 	}
    111 
    112 	if v2 != nil {
    113 		if v2.Name != nil && v2.Name.Defn == n {
    114 			v2.Type = t2
    115 		} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
    116 			yyerror("cannot assign type %v to %L in range%s", t2, v2, why)
    117 		}
    118 		checkassign(n, v2)
    119 	}
    120 
    121 	// second half of dance
    122 out:
    123 	n.Typecheck = 1
    124 	ls = n.List.Slice()
    125 	for i1, n1 := range ls {
    126 		if n1.Typecheck == 0 {
    127 			ls[i1] = typecheck(ls[i1], Erv|Easgn)
    128 		}
    129 	}
    130 
    131 	decldepth++
    132 	typecheckslice(n.Nbody.Slice(), Etop)
    133 	decldepth--
    134 }
    135 
    136 func walkrange(n *Node) {
    137 	// variable name conventions:
    138 	//	ohv1, hv1, hv2: hidden (old) val 1, 2
    139 	//	ha, hit: hidden aggregate, iterator
    140 	//	hn, hp: hidden len, pointer
    141 	//	hb: hidden bool
    142 	//	a, v1, v2: not hidden aggregate, val 1, 2
    143 
    144 	t := n.Type
    145 
    146 	a := n.Right
    147 	lno := setlineno(a)
    148 	n.Right = nil
    149 
    150 	var v1 *Node
    151 	if n.List.Len() != 0 {
    152 		v1 = n.List.First()
    153 	}
    154 	var v2 *Node
    155 	if n.List.Len() > 1 && !isblank(n.List.Second()) {
    156 		v2 = n.List.Second()
    157 	}
    158 
    159 	// n.List has no meaning anymore, clear it
    160 	// to avoid erroneous processing by racewalk.
    161 	n.List.Set(nil)
    162 
    163 	var body []*Node
    164 	var init []*Node
    165 	switch t.Etype {
    166 	default:
    167 		Fatalf("walkrange")
    168 
    169 	case TARRAY, TSLICE:
    170 		if memclrrange(n, v1, v2, a) {
    171 			lineno = lno
    172 			return
    173 		}
    174 
    175 		// orderstmt arranged for a copy of the array/slice variable if needed.
    176 		ha := a
    177 
    178 		hv1 := temp(Types[TINT])
    179 		hn := temp(Types[TINT])
    180 		var hp *Node
    181 
    182 		init = append(init, nod(OAS, hv1, nil))
    183 		init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
    184 		if v2 != nil {
    185 			hp = temp(ptrto(n.Type.Elem()))
    186 			tmp := nod(OINDEX, ha, nodintconst(0))
    187 			tmp.Bounded = true
    188 			init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
    189 		}
    190 
    191 		n.Left = nod(OLT, hv1, hn)
    192 		n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
    193 		if v1 == nil {
    194 			body = nil
    195 		} else if v2 == nil {
    196 			body = []*Node{nod(OAS, v1, hv1)}
    197 		} else {
    198 			a := nod(OAS2, nil, nil)
    199 			a.List.Set([]*Node{v1, v2})
    200 			a.Rlist.Set([]*Node{hv1, nod(OIND, hp, nil)})
    201 			body = []*Node{a}
    202 
    203 			// Advance pointer as part of increment.
    204 			// We used to advance the pointer before executing the loop body,
    205 			// but doing so would make the pointer point past the end of the
    206 			// array during the final iteration, possibly causing another unrelated
    207 			// piece of memory not to be garbage collected until the loop finished.
    208 			// Advancing during the increment ensures that the pointer p only points
    209 			// pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
    210 			// after which p is dead, so it cannot confuse the collector.
    211 			tmp := nod(OADD, hp, nodintconst(t.Elem().Width))
    212 
    213 			tmp.Type = hp.Type
    214 			tmp.Typecheck = 1
    215 			tmp.Right.Type = Types[Tptr]
    216 			tmp.Right.Typecheck = 1
    217 			a = nod(OAS, hp, tmp)
    218 			a = typecheck(a, Etop)
    219 			n.Right.Ninit.Set1(a)
    220 		}
    221 
    222 	case TMAP:
    223 		// orderstmt allocated the iterator for us.
    224 		// we only use a once, so no copy needed.
    225 		ha := a
    226 
    227 		th := hiter(t)
    228 		hit := prealloc[n]
    229 		hit.Type = th
    230 		n.Left = nil
    231 		keysym := th.Field(0).Sym // depends on layout of iterator struct.  See reflect.go:hiter
    232 		valsym := th.Field(1).Sym // ditto
    233 
    234 		fn := syslook("mapiterinit")
    235 
    236 		fn = substArgTypes(fn, t.Key(), t.Val(), th)
    237 		init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
    238 		n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
    239 
    240 		fn = syslook("mapiternext")
    241 		fn = substArgTypes(fn, th)
    242 		n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
    243 
    244 		key := nodSym(ODOT, hit, keysym)
    245 		key = nod(OIND, key, nil)
    246 		if v1 == nil {
    247 			body = nil
    248 		} else if v2 == nil {
    249 			body = []*Node{nod(OAS, v1, key)}
    250 		} else {
    251 			val := nodSym(ODOT, hit, valsym)
    252 			val = nod(OIND, val, nil)
    253 			a := nod(OAS2, nil, nil)
    254 			a.List.Set([]*Node{v1, v2})
    255 			a.Rlist.Set([]*Node{key, val})
    256 			body = []*Node{a}
    257 		}
    258 
    259 	case TCHAN:
    260 		// orderstmt arranged for a copy of the channel variable.
    261 		ha := a
    262 
    263 		n.Left = nil
    264 
    265 		hv1 := temp(t.Elem())
    266 		hv1.Typecheck = 1
    267 		if haspointers(t.Elem()) {
    268 			init = append(init, nod(OAS, hv1, nil))
    269 		}
    270 		hb := temp(Types[TBOOL])
    271 
    272 		n.Left = nod(ONE, hb, nodbool(false))
    273 		a := nod(OAS2RECV, nil, nil)
    274 		a.Typecheck = 1
    275 		a.List.Set([]*Node{hv1, hb})
    276 		a.Rlist.Set1(nod(ORECV, ha, nil))
    277 		n.Left.Ninit.Set1(a)
    278 		if v1 == nil {
    279 			body = nil
    280 		} else {
    281 			body = []*Node{nod(OAS, v1, hv1)}
    282 		}
    283 		// Zero hv1. This prevents hv1 from being the sole, inaccessible
    284 		// reference to an otherwise GC-able value during the next channel receive.
    285 		// See issue 15281.
    286 		body = append(body, nod(OAS, hv1, nil))
    287 
    288 	case TSTRING:
    289 		// Transform string range statements like "for v1, v2 = range a" into
    290 		//
    291 		// ha := a
    292 		// for hv1 := 0; hv1 < len(ha); {
    293 		//   v1 = hv1
    294 		//   hv2 := rune(ha[hv1])
    295 		//   if hv2 < utf8.RuneSelf {
    296 		//      hv1++
    297 		//   } else {
    298 		//      hv2, hv1 = decoderune(ha, hv1)
    299 		//   }
    300 		//   v2 = hv2
    301 		//   // original body
    302 		// }
    303 
    304 		// orderstmt arranged for a copy of the string variable.
    305 		ha := a
    306 
    307 		hv1 := temp(Types[TINT])
    308 		hv2 := temp(runetype)
    309 
    310 		// hv1 := 0
    311 		init = append(init, nod(OAS, hv1, nil))
    312 
    313 		// hv1 < len(ha)
    314 		n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
    315 
    316 		if v1 != nil {
    317 			// v1 = hv1
    318 			body = append(body, nod(OAS, v1, hv1))
    319 		}
    320 
    321 		// hv2 := ha[hv1]
    322 		nind := nod(OINDEX, ha, hv1)
    323 		nind.Bounded = true
    324 		body = append(body, nod(OAS, hv2, conv(nind, runetype)))
    325 
    326 		// if hv2 < utf8.RuneSelf
    327 		nif := nod(OIF, nil, nil)
    328 		nif.Left = nod(OLT, nind, nodintconst(utf8.RuneSelf))
    329 
    330 		// hv1++
    331 		nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
    332 
    333 		// } else {
    334 		eif := nod(OAS2, nil, nil)
    335 		nif.Rlist.Set1(eif)
    336 
    337 		// hv2, hv1 = decoderune(ha, hv1)
    338 		eif.List.Set2(hv2, hv1)
    339 		fn := syslook("decoderune")
    340 		eif.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
    341 
    342 		body = append(body, nif)
    343 
    344 		if v2 != nil {
    345 			// v2 = hv2
    346 			body = append(body, nod(OAS, v2, hv2))
    347 		}
    348 	}
    349 
    350 	n.Op = OFOR
    351 	typecheckslice(init, Etop)
    352 	n.Ninit.Append(init...)
    353 	typecheckslice(n.Left.Ninit.Slice(), Etop)
    354 	n.Left = typecheck(n.Left, Erv)
    355 	n.Right = typecheck(n.Right, Etop)
    356 	typecheckslice(body, Etop)
    357 	n.Nbody.Prepend(body...)
    358 	n = walkstmt(n)
    359 
    360 	lineno = lno
    361 }
    362 
    363 // Lower n into runtimememclr if possible, for
    364 // fast zeroing of slices and arrays (issue 5373).
    365 // Look for instances of
    366 //
    367 // for i := range a {
    368 // 	a[i] = zero
    369 // }
    370 //
    371 // in which the evaluation of a is side-effect-free.
    372 //
    373 // Parameters are as in walkrange: "for v1, v2 = range a".
    374 func memclrrange(n, v1, v2, a *Node) bool {
    375 	if Debug['N'] != 0 || instrumenting {
    376 		return false
    377 	}
    378 	if v1 == nil || v2 != nil {
    379 		return false
    380 	}
    381 	if n.Nbody.Len() == 0 || n.Nbody.First() == nil || n.Nbody.Len() > 1 {
    382 		return false
    383 	}
    384 	stmt := n.Nbody.First() // only stmt in body
    385 	if stmt.Op != OAS || stmt.Left.Op != OINDEX {
    386 		return false
    387 	}
    388 	if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
    389 		return false
    390 	}
    391 	elemsize := n.Type.Elem().Width
    392 	if elemsize <= 0 || !iszero(stmt.Right) {
    393 		return false
    394 	}
    395 
    396 	// Convert to
    397 	// if len(a) != 0 {
    398 	// 	hp = &a[0]
    399 	// 	hn = len(a)*sizeof(elem(a))
    400 	// 	memclr{NoHeap,Has}Pointers(hp, hn)
    401 	// 	i = len(a) - 1
    402 	// }
    403 	n.Op = OIF
    404 
    405 	n.Nbody.Set(nil)
    406 	n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
    407 
    408 	// hp = &a[0]
    409 	hp := temp(ptrto(Types[TUINT8]))
    410 
    411 	tmp := nod(OINDEX, a, nodintconst(0))
    412 	tmp.Bounded = true
    413 	tmp = nod(OADDR, tmp, nil)
    414 	tmp = nod(OCONVNOP, tmp, nil)
    415 	tmp.Type = ptrto(Types[TUINT8])
    416 	n.Nbody.Append(nod(OAS, hp, tmp))
    417 
    418 	// hn = len(a) * sizeof(elem(a))
    419 	hn := temp(Types[TUINTPTR])
    420 
    421 	tmp = nod(OLEN, a, nil)
    422 	tmp = nod(OMUL, tmp, nodintconst(elemsize))
    423 	tmp = conv(tmp, Types[TUINTPTR])
    424 	n.Nbody.Append(nod(OAS, hn, tmp))
    425 
    426 	var fn *Node
    427 	if haspointers(a.Type.Elem()) {
    428 		// memclrHasPointers(hp, hn)
    429 		fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
    430 	} else {
    431 		// memclrNoHeapPointers(hp, hn)
    432 		fn = mkcall("memclrNoHeapPointers", nil, nil, hp, hn)
    433 	}
    434 
    435 	n.Nbody.Append(fn)
    436 
    437 	// i = len(a) - 1
    438 	v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, nil), nodintconst(1)))
    439 
    440 	n.Nbody.Append(v1)
    441 
    442 	n.Left = typecheck(n.Left, Erv)
    443 	typecheckslice(n.Nbody.Slice(), Etop)
    444 	n = walkstmt(n)
    445 	return true
    446 }
    447