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