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