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