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

Fixes #885.

R=ken2
CC=golang-dev
https://golang.org/cl/1680048
diff --git a/test/range.go b/test/range.go
index 9093d71..91ccd63 100644
--- a/test/range.go
+++ b/test/range.go
@@ -32,18 +32,59 @@
 	}
 }
 
-// test that range over array only evaluates
+// test that range over slice only evaluates
 // the expression after "range" once.
 
 var nmake = 0
 
-func makearray() []int {
+func makeslice() []int {
 	nmake++
 	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() {
 	s := 0
+	nmake = 0
 	for _, v := range makearray() {
 		s += v
 	}
@@ -57,6 +98,151 @@
 	}
 }
 
+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
 // exactly once per iteration.
 
@@ -98,5 +284,14 @@
 func main() {
 	testchan()
 	testarray()
+	testarray1()
+	testarrayptr()
+	testarrayptr1()
+	testslice()
+	testslice1()
+	teststring()
+	teststring1()
+	testmap()
+	testmap1()
 	testcalls()
 }