Revert "cmd/compile: move hiter, hmap, and scase definitions into builtin.go"

This reverts commit f28bbb776a050cc3edca2bbe1241d81217a7a251.

Change-Id: I82fb81dcff3ddcaefef72949f1ef3a41bcd22301
Reviewed-on: https://go-review.googlesource.com/19849
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index d1827ef..4a6e56f 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -4,10 +4,6 @@
 
 const runtimeimport = "" +
 	"package runtime safe\n" +
-	"type @\"\".hbucket uint8\n" +
-	"type @\"\".hmap struct { @\"\".count int; @\"\".flags uint8; B uint8; @\"\".hash0 uint32; @\"\".buckets *@\"\".hbucket; @\"\".oldbuckets *@\"\".hbucket; @\"\".nevacuate uintptr; @\"\".overflow *[2]*[]*@\"\".hbucket }\n" +
-	"type @\"\".hiter struct { @\"\".key *byte; @\"\".value *byte; @\"\".t *byte; @\"\".h *@\"\".hmap; @\"\".buckets *@\"\".hbucket; @\"\".bptr *@\"\".hbucket; @\"\".overflow [2]*[]*@\"\".hbucket; @\"\".startBucket uintptr; @\"\".offset uint8; @\"\".wrapped bool; B uint8; @\"\".i uint8; @\"\".bucket uintptr; @\"\".checkBucket uintptr }\n" +
-	"type @\"\".scase struct { @\"\".elem *byte; @\"\".c *byte; @\"\".pc uintptr; @\"\".kind uint16; @\"\".so uint16; @\"\".receivedp *bool; @\"\".releasetime int64 }\n" +
 	"func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" +
 	"func @\"\".panicindex ()\n" +
 	"func @\"\".panicslice ()\n" +
@@ -70,7 +66,7 @@
 	"func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" +
 	"func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
 	"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
-	"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *@\"\".hmap, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" +
+	"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" +
 	"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" +
 	"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
 	"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
@@ -80,9 +76,9 @@
 	"func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
 	"func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
 	"func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" +
-	"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *@\"\".hiter)\n" +
+	"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" +
 	"func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" +
-	"func @\"\".mapiternext (@\"\".hiter·1 *@\"\".hiter)\n" +
+	"func @\"\".mapiternext (@\"\".hiter·1 *any)\n" +
 	"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" +
 	"func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" +
 	"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" +
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index e067d0b..0fe6242 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -12,49 +12,6 @@
 
 // emitted by compiler, not referred to by go programs
 
-type hbucket byte // placeholder
-
-// Changes here must also be made in src/runtime/hashmap.go.
-type hmap struct {
-	count      int
-	flags      uint8
-	B          uint8
-	hash0      uint32
-	buckets    *hbucket
-	oldbuckets *hbucket
-	nevacuate  uintptr
-	overflow   *[2]*[]*hbucket
-}
-
-// Changes here must also be made in src/runtime/hashmap.go.
-type hiter struct {
-	key         *byte // field name known to walkrange
-	value       *byte // field name known to walkrange
-	t           *byte // *maptype
-	h           *hmap
-	buckets     *hbucket
-	bptr        *hbucket
-	overflow    [2]*[]*hbucket
-	startBucket uintptr
-	offset      uint8
-	wrapped     bool
-	B           uint8
-	i           uint8
-	bucket      uintptr
-	checkBucket uintptr
-}
-
-// Changes here must also be made in src/runtime/select.go.
-type scase struct {
-	elem        *byte
-	c           *byte
-	pc          uintptr
-	kind        uint16
-	so          uint16
-	receivedp   *bool
-	releasetime int64
-}
-
 func newobject(typ *byte) *any
 func panicindex()
 func panicslice()
@@ -128,7 +85,7 @@
 func efaceeq(i1 any, i2 any) (ret bool)
 
 // *byte is really *runtime.Type
-func makemap(mapType *byte, hint int64, mapbuf *hmap, bucketbuf *any) (hmap map[any]any)
+func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
 func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
 func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
 func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
@@ -138,9 +95,9 @@
 func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
 func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
 func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
-func mapiterinit(mapType *byte, hmap map[any]any, hiter *hiter)
+func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
 func mapdelete(mapType *byte, hmap map[any]any, key *any)
-func mapiternext(hiter *hiter)
+func mapiternext(hiter *any)
 
 // *byte is really *runtime.Type
 func makechan(chanType *byte, hint int64) (hchan chan any)
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 91035b5..c0a1170 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -647,6 +647,14 @@
 				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
 			}
 
+			if t.Map.Hmap == t {
+				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
+			}
+
+			if t.Map.Hiter == t {
+				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
+			}
+
 			Yyerror("unknown internal map type")
 		}
 
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index cdb9769..1523c5e 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -191,7 +191,9 @@
 
 	// TMAP
 	Bucket *Type // internal type representing a hash bucket
-	Map    *Type // link from hash bucket type back to the map type.
+	Hmap   *Type // internal type representing a Hmap (map header object)
+	Hiter  *Type // internal type representing hash iterator state
+	Map    *Type // link from the above 3 internal types back to the map type.
 
 	Maplineno   int32 // first use of TFORW as map key
 	Embedlineno int32 // first use of TFORW as embedded type
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 8c2eca2..4386bcf 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -223,28 +223,24 @@
 	case TMAP:
 		ha := a
 
-		th := syslook("hiter", 0).Type
-		keytype := t.Down
-		valtype := t.Type
-
+		th := hiter(t)
 		hit := prealloc[n]
 		hit.Type = th
 		n.Left = nil
-
-		// These depend on hiter's field names.  See builtin/runtime.go:hiter.
-		keyname := newname(Pkglookup("key", Runtimepkg))
-		valname := newname(Pkglookup("value", Runtimepkg))
+		keyname := newname(th.Type.Sym)      // depends on layout of iterator struct.  See reflect.go:hiter
+		valname := newname(th.Type.Down.Sym) // ditto
 
 		fn := syslook("mapiterinit", 1)
-		substArgTypes(fn, keytype, valtype)
+
+		substArgTypes(fn, t.Down, t.Type, th)
 		init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
 		n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
 
-		n.Right = mkcall("mapiternext", nil, nil, Nod(OADDR, hit, nil))
+		fn = syslook("mapiternext", 1)
+		substArgTypes(fn, th)
+		n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
 
 		key := Nod(ODOT, hit, keyname)
-		key = Nod(OCONVNOP, key, nil)
-		key.Type = Ptrto(keytype)
 		key = Nod(OIND, key, nil)
 		if v1 == nil {
 			body = nil
@@ -252,8 +248,6 @@
 			body = list1(Nod(OAS, v1, key))
 		} else {
 			val := Nod(ODOT, hit, valname)
-			val = Nod(OCONVNOP, val, nil)
-			val.Type = Ptrto(valtype)
 			val = Nod(OIND, val, nil)
 			a := Nod(OAS2, nil, nil)
 			a.List = list(list1(v1), v2)
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 369d015..8693e3c 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -149,6 +149,92 @@
 	return bucket
 }
 
+// Builds a type representing a Hmap structure for the given map type.
+// Make sure this stays in sync with ../../../../runtime/hashmap.go!
+func hmap(t *Type) *Type {
+	if t.Hmap != nil {
+		return t.Hmap
+	}
+
+	bucket := mapbucket(t)
+	var field [8]*Type
+	field[0] = makefield("count", Types[TINT])
+	field[1] = makefield("flags", Types[TUINT8])
+	field[2] = makefield("B", Types[TUINT8])
+	field[3] = makefield("hash0", Types[TUINT32])
+	field[4] = makefield("buckets", Ptrto(bucket))
+	field[5] = makefield("oldbuckets", Ptrto(bucket))
+	field[6] = makefield("nevacuate", Types[TUINTPTR])
+	field[7] = makefield("overflow", Types[TUNSAFEPTR])
+
+	h := typ(TSTRUCT)
+	h.Noalg = true
+	h.Local = t.Local
+	h.Type = field[0]
+	for n := int32(0); n < int32(len(field)-1); n++ {
+		field[n].Down = field[n+1]
+	}
+	field[len(field)-1].Down = nil
+	dowidth(h)
+	t.Hmap = h
+	h.Map = t
+	return h
+}
+
+func hiter(t *Type) *Type {
+	if t.Hiter != nil {
+		return t.Hiter
+	}
+
+	// build a struct:
+	// hiter {
+	//    key *Key
+	//    val *Value
+	//    t *MapType
+	//    h *Hmap
+	//    buckets *Bucket
+	//    bptr *Bucket
+	//    overflow0 unsafe.Pointer
+	//    overflow1 unsafe.Pointer
+	//    startBucket uintptr
+	//    stuff uintptr
+	//    bucket uintptr
+	//    checkBucket uintptr
+	// }
+	// must match ../../../../runtime/hashmap.go:hiter.
+	var field [12]*Type
+	field[0] = makefield("key", Ptrto(t.Down))
+
+	field[1] = makefield("val", Ptrto(t.Type))
+	field[2] = makefield("t", Ptrto(Types[TUINT8]))
+	field[3] = makefield("h", Ptrto(hmap(t)))
+	field[4] = makefield("buckets", Ptrto(mapbucket(t)))
+	field[5] = makefield("bptr", Ptrto(mapbucket(t)))
+	field[6] = makefield("overflow0", Types[TUNSAFEPTR])
+	field[7] = makefield("overflow1", Types[TUNSAFEPTR])
+	field[8] = makefield("startBucket", Types[TUINTPTR])
+	field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I
+	field[10] = makefield("bucket", Types[TUINTPTR])
+	field[11] = makefield("checkBucket", Types[TUINTPTR])
+
+	// build iterator struct holding the above fields
+	i := typ(TSTRUCT)
+
+	i.Noalg = true
+	i.Type = field[0]
+	for n := int32(0); n < int32(len(field)-1); n++ {
+		field[n].Down = field[n+1]
+	}
+	field[len(field)-1].Down = nil
+	dowidth(i)
+	if i.Width != int64(12*Widthptr) {
+		Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
+	}
+	t.Hiter = i
+	i.Map = t
+	return i
+}
+
 // f is method type, with receiver.
 // return function type, receiver as first argument (or not).
 func methodfunc(f *Type, receiver *Type) *Type {
@@ -1026,11 +1112,13 @@
 
 		s2 := dtypesym(t.Type)
 		s3 := dtypesym(mapbucket(t))
+		s4 := dtypesym(hmap(t))
 		ot = dcommontype(s, ot, t)
 		xt = ot - 2*Widthptr
 		ot = dsymptr(s, ot, s1, 0)
 		ot = dsymptr(s, ot, s2, 0)
 		ot = dsymptr(s, ot, s3, 0)
+		ot = dsymptr(s, ot, s4, 0)
 		if t.Down.Width > MAXKEYSIZE {
 			ot = duint8(s, ot, uint8(Widthptr))
 			ot = duint8(s, ot, 1) // indirect
@@ -1251,10 +1339,8 @@
 		hashfunc = typesymprefix(".hashfunc", t)
 		eqfunc = typesymprefix(".eqfunc", t)
 
-		if Debug['A'] == 0 {
-			genhash(hash, t)
-			geneq(eq, t)
-		}
+		genhash(hash, t)
+		geneq(eq, t)
 
 		// make Go funcs (closures) for calling hash and equal from Go
 		dsymptr(hashfunc, 0, hash, 0)
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index 9a619a6..e770c8f 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -318,9 +318,35 @@
 	lineno = int32(lno)
 }
 
-// Keep in sync with src/runtime/select.go.
+// Keep in sync with src/runtime/runtime2.go and src/runtime/select.go.
 func selecttype(size int32) *Type {
-	scase := syslook("scase", 0)
+	// TODO(dvyukov): it's possible to generate SudoG and Scase only once
+	// and then cache; and also cache Select per size.
+	sudog := Nod(OTSTRUCT, nil, nil)
+
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("g")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("selectdone")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("next")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("prev")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("nrelease")), typenod(Types[TINT32])))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8]))))
+	typecheck(&sudog, Etype)
+	sudog.Type.Noalg = true
+	sudog.Type.Local = true
+
+	scase := Nod(OTSTRUCT, nil, nil)
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
+	typecheck(&scase, Etype)
+	scase.Type.Noalg = true
+	scase.Type.Local = true
 
 	sel := Nod(OTSTRUCT, nil, nil)
 	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16])))
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 0415fd3..b6a2648 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -1413,21 +1413,16 @@
 	if t == nil {
 		return nil
 	}
-	if t.Etype == TANY {
-		nt := shallow(t)
-		nt.Copyany = true
-		return nt
-	}
-	if t.Sym != nil {
-		// share named types
-		return t
-	}
 
 	var nt *Type
 	switch t.Etype {
 	default:
 		nt = t // share from here down
 
+	case TANY:
+		nt = shallow(t)
+		nt.Copyany = true
+
 	case TPTR32, TPTR64, TCHAN, TARRAY:
 		nt = shallow(t)
 		nt.Type = deep(t.Type)
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index f3112c3..f324d5e 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -1375,7 +1375,7 @@
 		r := nodnil() // bucket buffer
 		if n.Esc == EscNone {
 			// Allocate hmap buffer on stack.
-			var_ := temp(syslook("hmap", 0).Type)
+			var_ := temp(hmap(t))
 
 			a = Nod(OAS, var_, nil) // zero temp
 			typecheck(&a, Etop)
@@ -1393,7 +1393,7 @@
 			r = Nod(OADDR, var_, nil)
 		}
 
-		substArgTypes(fn, mapbucket(t), t.Down, t.Type)
+		substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
 		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
 
 	case OMAKESLICE: