1
0
mirror of https://github.com/golang/go synced 2024-11-21 19:14:44 -07:00

gc: implement new len spec, range bug fix, optimization

Fixes #885.

R=ken2
CC=golang-dev
https://golang.org/cl/1680048
This commit is contained in:
Russ Cox 2010-07-01 18:04:25 -07:00
parent f4429181df
commit 81c3e8cabc
4 changed files with 227 additions and 9 deletions

View File

@ -24,6 +24,8 @@ typecheckrange(Node *n)
typecheck(&n->right, Erv); typecheck(&n->right, Erv);
if((t = n->right->type) == T) if((t = n->right->type) == T)
goto out; goto out;
if(isptr[t->etype] && isfixedarray(t->type))
t = t->type;
n->type = t; n->type = t;
switch(t->etype) { switch(t->etype) {
@ -104,9 +106,6 @@ walkrange(Node *n)
a = nod(OCONV, n->right, N); a = nod(OCONV, n->right, N);
a->type = types[TSTRING]; a->type = types[TSTRING];
} }
ha = nod(OXXX, N, N);
tempname(ha, a->type);
init = list(init, nod(OAS, ha, a));
v1 = n->list->n; v1 = n->list->n;
hv1 = N; hv1 = N;
@ -116,6 +115,16 @@ walkrange(Node *n)
v2 = n->list->next->n; v2 = n->list->next->n;
hv2 = N; hv2 = N;
if(v2 == N && t->etype == TARRAY) {
// will have just one reference to argument.
// no need to make a potentially expensive copy.
ha = a;
} else {
ha = nod(OXXX, N, N);
tempname(ha, a->type);
init = list(init, nod(OAS, ha, a));
}
switch(t->etype) { switch(t->etype) {
default: default:
fatal("walkrange"); fatal("walkrange");
@ -131,7 +140,7 @@ walkrange(Node *n)
init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
if(v2) { if(v2) {
hp = nod(OXXX, N, N); hp = nod(OXXX, N, N);
tempname(hp, ptrto(a->type->type)); tempname(hp, ptrto(n->type->type));
tmp = nod(OINDEX, ha, nodintconst(0)); tmp = nod(OINDEX, ha, nodintconst(0));
tmp->etype = 1; // no bounds check tmp->etype = 1; // no bounds check
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));

View File

@ -802,7 +802,7 @@ reswitch:
nodconst(n, types[TINT], l->val.u.sval->len); nodconst(n, types[TINT], l->val.u.sval->len);
break; break;
case TARRAY: case TARRAY:
if(t->bound >= 0) if(t->bound >= 0 && l->op == ONAME)
nodconst(n, types[TINT], t->bound); nodconst(n, types[TINT], t->bound);
break; break;
} }

View File

@ -594,8 +594,6 @@ walkexpr(Node **np, NodeList **init)
case OMINUS: case OMINUS:
case OPLUS: case OPLUS:
case OCOM: case OCOM:
case OLEN:
case OCAP:
case OREAL: case OREAL:
case OIMAG: case OIMAG:
case ODOT: case ODOT:
@ -606,6 +604,22 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init); walkexpr(&n->left, init);
goto ret; goto ret;
case OLEN:
case OCAP:
walkexpr(&n->left, init);
// replace len(*[10]int) with 10.
// delayed until now to preserve side effects.
t = n->left->type;
if(isptr[t->etype])
t = t->type;
if(isfixedarray(t)) {
safeexpr(n->left, init);
nodconst(n, n->type, t->bound);
n->typecheck = 1;
}
goto ret;
case OLSH: case OLSH:
case ORSH: case ORSH:
case OAND: case OAND:

View File

@ -32,18 +32,59 @@ func testchan() {
} }
} }
// test that range over array only evaluates // test that range over slice only evaluates
// the expression after "range" once. // the expression after "range" once.
var nmake = 0 var nmake = 0
func makearray() []int { func makeslice() []int {
nmake++ nmake++
return []int{1, 2, 3, 4, 5} return []int{1, 2, 3, 4, 5}
} }
func testslice() {
s := 0
nmake = 0
for _, v := range makeslice() {
s += v
}
if nmake != 1 {
println("range called makeslice", nmake, "times")
panic("fail")
}
if s != 15 {
println("wrong sum ranging over makeslice")
panic("fail")
}
}
func testslice1() {
s := 0
nmake = 0
for i := range makeslice() {
s += i
}
if nmake != 1 {
println("range called makeslice", nmake, "times")
panic("fail")
}
if s != 10 {
println("wrong sum ranging over makeslice")
panic("fail")
}
}
// test that range over array only evaluates
// the expression after "range" once.
func makearray() [5]int {
nmake++
return [5]int{1, 2, 3, 4, 5}
}
func testarray() { func testarray() {
s := 0 s := 0
nmake = 0
for _, v := range makearray() { for _, v := range makearray() {
s += v s += v
} }
@ -57,6 +98,151 @@ func testarray() {
} }
} }
func testarray1() {
s := 0
nmake = 0
for i := range makearray() {
s += i
}
if nmake != 1 {
println("range called makearray", nmake, "times")
panic("fail")
}
if s != 10 {
println("wrong sum ranging over makearray")
panic("fail")
}
}
func makearrayptr() *[5]int {
nmake++
return &[5]int{1, 2, 3, 4, 5}
}
func testarrayptr() {
nmake = 0
x := len(makearrayptr())
if x != 5 || nmake != 1 {
println("len called makearrayptr", nmake, "times and got len", x)
panic("fail")
}
nmake = 0
x = cap(makearrayptr())
if x != 5 || nmake != 1 {
println("cap called makearrayptr", nmake, "times and got len", x)
panic("fail")
}
s := 0
nmake = 0
for _, v := range makearrayptr() {
s += v
}
if nmake != 1 {
println("range called makearrayptr", nmake, "times")
panic("fail")
}
if s != 15 {
println("wrong sum ranging over makearrayptr")
panic("fail")
}
}
func testarrayptr1() {
s := 0
nmake = 0
for i := range makearrayptr() {
s += i
}
if nmake != 1 {
println("range called makearrayptr", nmake, "times")
panic("fail")
}
if s != 10 {
println("wrong sum ranging over makearrayptr")
panic("fail")
}
}
// test that range over string only evaluates
// the expression after "range" once.
func makestring() string {
nmake++
return "abcd☺"
}
func teststring() {
s := 0
nmake = 0
for _, v := range makestring() {
s += v
}
if nmake != 1 {
println("range called makestring", nmake, "times")
panic("fail")
}
if s != 'a'+'b'+'c'+'d'+'☺' {
println("wrong sum ranging over makestring")
panic("fail")
}
}
func teststring1() {
s := 0
nmake = 0
for i := range makestring() {
s += i
}
if nmake != 1 {
println("range called makestring", nmake, "times")
panic("fail")
}
if s != 10 {
println("wrong sum ranging over makestring")
panic("fail")
}
}
// test that range over map only evaluates
// the expression after "range" once.
func makemap() map[int]int {
nmake++
return map[int]int{0:'a', 1:'b', 2:'c', 3:'d', 4:'☺'}
}
func testmap() {
s := 0
nmake = 0
for _, v := range makemap() {
s += v
}
if nmake != 1 {
println("range called makemap", nmake, "times")
panic("fail")
}
if s != 'a'+'b'+'c'+'d'+'☺' {
println("wrong sum ranging over makemap")
panic("fail")
}
}
func testmap1() {
s := 0
nmake = 0
for i := range makemap() {
s += i
}
if nmake != 1 {
println("range called makemap", nmake, "times")
panic("fail")
}
if s != 10 {
println("wrong sum ranging over makemap")
panic("fail")
}
}
// test that range evaluates the index and value expressions // test that range evaluates the index and value expressions
// exactly once per iteration. // exactly once per iteration.
@ -98,5 +284,14 @@ func testcalls() {
func main() { func main() {
testchan() testchan()
testarray() testarray()
testarray1()
testarrayptr()
testarrayptr1()
testslice()
testslice1()
teststring()
teststring1()
testmap()
testmap1()
testcalls() testcalls()
} }