github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/gc/range.c (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 /* 6 * range 7 */ 8 9 #include <u.h> 10 #include <libc.h> 11 #include "go.h" 12 13 void 14 typecheckrange(Node *n) 15 { 16 char *why; 17 Type *t, *t1, *t2; 18 Node *v1, *v2; 19 NodeList *ll; 20 21 // delicate little dance. see typecheckas2 22 for(ll=n->list; ll; ll=ll->next) 23 if(ll->n->defn != n) 24 typecheck(&ll->n, Erv | Easgn); 25 26 typecheck(&n->right, Erv); 27 if((t = n->right->type) == T) 28 goto out; 29 if(isptr[t->etype] && isfixedarray(t->type)) 30 t = t->type; 31 n->type = t; 32 33 switch(t->etype) { 34 default: 35 yyerror("cannot range over %lN", n->right); 36 goto out; 37 38 case TARRAY: 39 t1 = types[TINT]; 40 t2 = t->type; 41 break; 42 43 case TMAP: 44 t1 = t->down; 45 t2 = t->type; 46 break; 47 48 case TCHAN: 49 if(!(t->chan & Crecv)) { 50 yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type); 51 goto out; 52 } 53 t1 = t->type; 54 t2 = nil; 55 if(count(n->list) == 2) 56 goto toomany; 57 break; 58 59 case TSTRING: 60 t1 = types[TINT]; 61 t2 = runetype; 62 break; 63 } 64 65 if(count(n->list) > 2) { 66 toomany: 67 yyerror("too many variables in range"); 68 } 69 70 v1 = N; 71 if(n->list) 72 v1 = n->list->n; 73 v2 = N; 74 if(n->list && n->list->next) 75 v2 = n->list->next->n; 76 77 // this is not only a optimization but also a requirement in the spec. 78 // "if the second iteration variable is the blank identifier, the range 79 // clause is equivalent to the same clause with only the first variable 80 // present." 81 if(isblank(v2)) { 82 if(v1 != N) 83 n->list = list1(v1); 84 v2 = N; 85 } 86 87 if(v1) { 88 if(v1->defn == n) 89 v1->type = t1; 90 else if(v1->type != T && assignop(t1, v1->type, &why) == 0) 91 yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); 92 } 93 if(v2) { 94 if(v2->defn == n) 95 v2->type = t2; 96 else if(v2->type != T && assignop(t2, v2->type, &why) == 0) 97 yyerror("cannot assign type %T to %lN in range%s", t2, v2, why); 98 } 99 100 out: 101 typechecklist(n->nbody, Etop); 102 103 // second half of dance 104 n->typecheck = 1; 105 for(ll=n->list; ll; ll=ll->next) 106 if(ll->n->typecheck == 0) 107 typecheck(&ll->n, Erv | Easgn); 108 } 109 110 void 111 walkrange(Node *n) 112 { 113 Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 114 Node *ha, *hit; // hidden aggregate, iterator 115 Node *hn, *hp; // hidden len, pointer 116 Node *hb; // hidden bool 117 Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 118 Node *fn, *tmp; 119 Node *keyname, *valname; 120 Node *key, *val; 121 NodeList *body, *init; 122 Type *th, *t; 123 int lno; 124 125 t = n->type; 126 init = nil; 127 128 a = n->right; 129 lno = setlineno(a); 130 131 v1 = N; 132 if(n->list) 133 v1 = n->list->n; 134 v2 = N; 135 if(n->list && n->list->next && !isblank(n->list->next->n)) 136 v2 = n->list->next->n; 137 // n->list has no meaning anymore, clear it 138 // to avoid erroneous processing by racewalk. 139 n->list = nil; 140 hv2 = N; 141 142 switch(t->etype) { 143 default: 144 fatal("walkrange"); 145 146 case TARRAY: 147 // Lower n into runtime·memclr if possible, for 148 // fast zeroing of slices and arrays (issue 5373). 149 // Look for instances of 150 // 151 // for i := range a { 152 // a[i] = zero 153 // } 154 // 155 // in which the evaluation of a is side-effect-free. 156 if(!debug['N']) 157 if(!flag_race) 158 if(v1 != N) 159 if(v2 == N) 160 if(n->nbody != nil) 161 if(n->nbody->n != N) // at least one statement in body 162 if(n->nbody->next == nil) { // at most one statement in body 163 tmp = n->nbody->n; // first statement of body 164 if(tmp->op == OAS) 165 if(tmp->left->op == OINDEX) 166 if(samesafeexpr(tmp->left->left, a)) 167 if(samesafeexpr(tmp->left->right, v1)) 168 if(t->type->width > 0) 169 if(iszero(tmp->right)) { 170 // Convert to 171 // if len(a) != 0 { 172 // hp = &a[0] 173 // hn = len(a)*sizeof(elem(a)) 174 // memclr(hp, hn) 175 // i = len(a) - 1 176 // } 177 n->op = OIF; 178 n->nbody = nil; 179 n->ntest = nod(ONE, nod(OLEN, a, N), nodintconst(0)); 180 n->nincr = nil; 181 182 // hp = &a[0] 183 hp = temp(ptrto(types[TUINT8])); 184 tmp = nod(OINDEX, a, nodintconst(0)); 185 tmp->bounded = 1; 186 tmp = nod(OADDR, tmp, N); 187 tmp = nod(OCONVNOP, tmp, N); 188 tmp->type = ptrto(types[TUINT8]); 189 n->nbody = list(n->nbody, nod(OAS, hp, tmp)); 190 191 // hn = len(a) * sizeof(elem(a)) 192 hn = temp(types[TUINTPTR]); 193 tmp = nod(OLEN, a, N); 194 tmp = nod(OMUL, tmp, nodintconst(t->type->width)); 195 tmp = conv(tmp, types[TUINTPTR]); 196 n->nbody = list(n->nbody, nod(OAS, hn, tmp)); 197 198 // memclr(hp, hn) 199 fn = mkcall("memclr", T, nil, hp, hn); 200 n->nbody = list(n->nbody, fn); 201 202 // i = len(a) - 1 203 v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, N), nodintconst(1))); 204 n->nbody = list(n->nbody, v1); 205 206 typecheck(&n->ntest, Erv); 207 typechecklist(n->nbody, Etop); 208 walkstmt(&n); 209 lineno = lno; 210 return; 211 } 212 } 213 214 // orderstmt arranged for a copy of the array/slice variable if needed. 215 ha = a; 216 hv1 = temp(types[TINT]); 217 hn = temp(types[TINT]); 218 hp = nil; 219 220 init = list(init, nod(OAS, hv1, N)); 221 init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); 222 if(v2) { 223 hp = temp(ptrto(n->type->type)); 224 tmp = nod(OINDEX, ha, nodintconst(0)); 225 tmp->bounded = 1; 226 init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); 227 } 228 229 n->ntest = nod(OLT, hv1, hn); 230 n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); 231 if(v1 == N) 232 body = nil; 233 else if(v2 == N) 234 body = list1(nod(OAS, v1, hv1)); 235 else { 236 a = nod(OAS2, N, N); 237 a->list = list(list1(v1), v2); 238 a->rlist = list(list1(hv1), nod(OIND, hp, N)); 239 body = list1(a); 240 241 // Advance pointer as part of increment. 242 // We used to advance the pointer before executing the loop body, 243 // but doing so would make the pointer point past the end of the 244 // array during the final iteration, possibly causing another unrelated 245 // piece of memory not to be garbage collected until the loop finished. 246 // Advancing during the increment ensures that the pointer p only points 247 // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;", 248 // after which p is dead, so it cannot confuse the collector. 249 tmp = nod(OADD, hp, nodintconst(t->type->width)); 250 tmp->type = hp->type; 251 tmp->typecheck = 1; 252 tmp->right->type = types[tptr]; 253 tmp->right->typecheck = 1; 254 a = nod(OAS, hp, tmp); 255 typecheck(&a, Etop); 256 n->nincr->ninit = list1(a); 257 } 258 break; 259 260 case TMAP: 261 // orderstmt allocated the iterator for us. 262 // we only use a once, so no copy needed. 263 ha = a; 264 th = hiter(t); 265 hit = n->alloc; 266 hit->type = th; 267 n->left = N; 268 keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter 269 valname = newname(th->type->down->sym); // ditto 270 271 fn = syslook("mapiterinit", 1); 272 argtype(fn, t->down); 273 argtype(fn, t->type); 274 argtype(fn, th); 275 init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N))); 276 n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil()); 277 278 fn = syslook("mapiternext", 1); 279 argtype(fn, th); 280 n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); 281 282 key = nod(ODOT, hit, keyname); 283 key = nod(OIND, key, N); 284 if(v1 == N) 285 body = nil; 286 else if(v2 == N) { 287 body = list1(nod(OAS, v1, key)); 288 } else { 289 val = nod(ODOT, hit, valname); 290 val = nod(OIND, val, N); 291 a = nod(OAS2, N, N); 292 a->list = list(list1(v1), v2); 293 a->rlist = list(list1(key), val); 294 body = list1(a); 295 } 296 break; 297 298 case TCHAN: 299 // orderstmt arranged for a copy of the channel variable. 300 ha = a; 301 n->ntest = N; 302 303 hv1 = temp(t->type); 304 hv1->typecheck = 1; 305 if(haspointers(t->type)) 306 init = list(init, nod(OAS, hv1, N)); 307 hb = temp(types[TBOOL]); 308 309 n->ntest = nod(ONE, hb, nodbool(0)); 310 a = nod(OAS2RECV, N, N); 311 a->typecheck = 1; 312 a->list = list(list1(hv1), hb); 313 a->rlist = list1(nod(ORECV, ha, N)); 314 n->ntest->ninit = list1(a); 315 if(v1 == N) 316 body = nil; 317 else 318 body = list1(nod(OAS, v1, hv1)); 319 break; 320 321 case TSTRING: 322 // orderstmt arranged for a copy of the string variable. 323 ha = a; 324 325 ohv1 = temp(types[TINT]); 326 327 hv1 = temp(types[TINT]); 328 init = list(init, nod(OAS, hv1, N)); 329 330 if(v2 == N) 331 a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); 332 else { 333 hv2 = temp(runetype); 334 a = nod(OAS2, N, N); 335 a->list = list(list1(hv1), hv2); 336 fn = syslook("stringiter2", 0); 337 a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); 338 } 339 n->ntest = nod(ONE, hv1, nodintconst(0)); 340 n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); 341 342 343 body = nil; 344 if(v1 != N) 345 body = list1(nod(OAS, v1, ohv1)); 346 if(v2 != N) 347 body = list(body, nod(OAS, v2, hv2)); 348 break; 349 } 350 351 n->op = OFOR; 352 typechecklist(init, Etop); 353 n->ninit = concat(n->ninit, init); 354 typechecklist(n->ntest->ninit, Etop); 355 typecheck(&n->ntest, Erv); 356 typecheck(&n->nincr, Etop); 357 typechecklist(body, Etop); 358 n->nbody = concat(body, n->nbody); 359 walkstmt(&n); 360 361 lineno = lno; 362 } 363