gc: implement nil map support

The spec has defined nil maps this way for months.
I'm behind.

R=ken2
CC=golang-dev
https://golang.org/cl/4901052
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 6419873..84eef69 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -57,12 +57,12 @@
 	"func \"\".efaceeq (i1 any, i2 any) bool\n"
 	"func \"\".ifacethash (i1 any) uint32\n"
 	"func \"\".efacethash (i1 any) uint32\n"
-	"func \"\".makemap (key *uint8, val *uint8, hint int64) map[any] any\n"
-	"func \"\".mapaccess1 (hmap map[any] any, key any) any\n"
-	"func \"\".mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
-	"func \"\".mapassign1 (hmap map[any] any, key any, val any)\n"
-	"func \"\".mapassign2 (hmap map[any] any, key any, val any, pres bool)\n"
-	"func \"\".mapiterinit (hmap map[any] any, hiter *any)\n"
+	"func \"\".makemap (mapType *uint8, hint int64) map[any] any\n"
+	"func \"\".mapaccess1 (mapType *uint8, hmap map[any] any, key any) any\n"
+	"func \"\".mapaccess2 (mapType *uint8, hmap map[any] any, key any) (val any, pres bool)\n"
+	"func \"\".mapassign1 (mapType *uint8, hmap map[any] any, key any, val any)\n"
+	"func \"\".mapassign2 (mapType *uint8, hmap map[any] any, key any, val any, pres bool)\n"
+	"func \"\".mapiterinit (mapType *uint8, hmap map[any] any, hiter *any)\n"
 	"func \"\".mapiternext (hiter *any)\n"
 	"func \"\".mapiter1 (hiter *any) any\n"
 	"func \"\".mapiter2 (hiter *any) (key any, val any)\n"
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index fb33e4e..5ce693a 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -175,7 +175,7 @@
 		argtype(fn, t->down);
 		argtype(fn, t->type);
 		argtype(fn, th);
-		init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N)));
+		init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
 		n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
 
 		fn = syslook("mapiternext", 1);
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 7254f87..64098ab 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -80,12 +80,12 @@
 func efacethash(i1 any) (ret uint32)
 
 // *byte is really *runtime.Type
-func makemap(key, val *byte, hint int64) (hmap map[any]any)
-func mapaccess1(hmap map[any]any, key any) (val any)
-func mapaccess2(hmap map[any]any, key any) (val any, pres bool)
-func mapassign1(hmap map[any]any, key any, val any)
-func mapassign2(hmap map[any]any, key any, val any, pres bool)
-func mapiterinit(hmap map[any]any, hiter *any)
+func makemap(mapType *byte, hint int64) (hmap map[any]any)
+func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any)
+func mapaccess2(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 mapassign2(mapType *byte, hmap map[any]any, key any, val any, pres bool)
+func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
 func mapiternext(hiter *any)
 func mapiter1(hiter *any) (key any)
 func mapiter2(hiter *any) (key any, val any)
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 0383e5a..7a39db2 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -604,7 +604,7 @@
 		walkexprlistsafe(n->list, init);
 		walkexpr(&r->left, init);
 		fn = mapfn("mapaccess2", r->left->type);
-		r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
+		r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left, r->right);
 		n->rlist = list1(r);
 		n->op = OAS2FUNC;
 		goto as2func;
@@ -617,7 +617,7 @@
 		walkexprlistsafe(n->list, init);
 		l = n->list->n;
 		t = l->left->type;
-		n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
+		n = mkcall1(mapfn("mapassign2", t), T, init, typename(t), l->left, l->right, n->rlist->n, n->rlist->next->n);
 		goto ret;
 
 	case OAS2DOTTYPE:
@@ -852,7 +852,7 @@
 			goto ret;
 
 		t = n->left->type;
-		n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
+		n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
 		goto ret;
 
 	case ORECV:
@@ -1090,8 +1090,7 @@
 		argtype(fn, t->type);	// any-2
 
 		n = mkcall1(fn, n->type, init,
-			typename(t->down),	// key type
-			typename(t->type),		// value type
+			typename(n->type),
 			conv(n->left, types[TINT64]));
 		goto ret;
 
@@ -1697,6 +1696,7 @@
 
 	if(n->left->op == OINDEXMAP) {
 		n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
+			typename(n->left->left->type),
 			n->left->left, n->left->right, n->right);
 		goto out;
 	}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 87d12bb..e40b434 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -977,7 +977,7 @@
 
 	flag := (iv.flag | ikey.flag) & flagRO
 	elemType := typ.Elem()
-	elemWord, ok := mapaccess(iv.word, ikey.word)
+	elemWord, ok := mapaccess(typ.runtimeType(), iv.word, ikey.word)
 	if !ok {
 		return Value{}
 	}
@@ -999,7 +999,7 @@
 	if m != 0 {
 		mlen = maplen(m)
 	}
-	it := mapiterinit(m)
+	it := mapiterinit(iv.typ.runtimeType(), m)
 	a := make([]Value, mlen)
 	var i int
 	for i = 0; i < len(a); i++ {
@@ -1309,7 +1309,7 @@
 		ival = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Elem(), ival)
 	}
 
-	mapassign(iv.word, ikey.word, ival.word, ival.kind != Invalid)
+	mapassign(iv.typ.runtimeType(), iv.word, ikey.word, ival.word, ival.kind != Invalid)
 }
 
 // SetUint sets v's underlying value to x.
@@ -1725,9 +1725,9 @@
 
 func makechan(typ *runtime.Type, size uint32) (ch iword)
 func makemap(t *runtime.Type) iword
-func mapaccess(m iword, key iword) (val iword, ok bool)
-func mapassign(m iword, key, val iword, ok bool)
-func mapiterinit(m iword) *byte
+func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)
+func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)
+func mapiterinit(t *runtime.Type, m iword) *byte
 func mapiterkey(it *byte) (key iword, ok bool)
 func mapiternext(it *byte)
 func maplen(m iword) int32
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 179a563..0c0e3e4 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -690,13 +690,17 @@
 
 static	int32	debug	= 0;
 
-// makemap(key, val *Type, hint uint32) (hmap *map[any]any);
+// makemap(typ *Type, hint uint32) (hmap *map[any]any);
 Hmap*
-runtime·makemap_c(Type *key, Type *val, int64 hint)
+runtime·makemap_c(MapType *typ, int64 hint)
 {
 	Hmap *h;
 	int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
 	void (*data_del)(uint32, void*, void*);
+	Type *key, *val;
+	
+	key = typ->key;
+	val = typ->elem;
 
 	if(hint < 0 || (int32)hint != hint)
 		runtime·panicstring("makemap: size out of range");
@@ -770,9 +774,9 @@
 
 // makemap(key, val *Type, hint int64) (hmap *map[any]any);
 void
-runtime·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
+runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
 {
-	ret = runtime·makemap_c(key, val, hint);
+	ret = runtime·makemap_c(typ, hint);
 	FLUSH(&ret);
 }
 
@@ -781,17 +785,22 @@
 void
 reflect·makemap(MapType *t, Hmap *ret)
 {
-	ret = runtime·makemap_c(t->key, t->elem, 0);
+	ret = runtime·makemap_c(t, 0);
 	FLUSH(&ret);
 }
 
 void
-runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
+runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
 {
 	byte *res;
+	Type *elem;
 
-	if(h == nil)
-		runtime·panicstring("lookup in nil map");
+	if(h == nil) {
+		elem = t->elem;
+		runtime·algarray[elem->alg].copy(elem->size, av, nil);
+		*pres = false;
+		return;
+	}
 
 	if(runtime·gcwaiting)
 		runtime·gosched();
@@ -809,18 +818,20 @@
 // mapaccess1(hmap *map[any]any, key any) (val any);
 #pragma textflag 7
 void
-runtime·mapaccess1(Hmap *h, ...)
+runtime·mapaccess1(MapType *t, Hmap *h, ...)
 {
 	byte *ak, *av;
 	bool pres;
 
-	if(h == nil)
-		runtime·panicstring("lookup in nil map");
+	if(h == nil) {
+		ak = (byte*)(&h + 1);
+		av = ak + runtime·rnd(t->key->size, Structrnd);
+	} else {
+		ak = (byte*)&h + h->ko1;
+		av = (byte*)&h + h->vo1;
+	}
 
-	ak = (byte*)&h + h->ko1;
-	av = (byte*)&h + h->vo1;
-
-	runtime·mapaccess(h, ak, av, &pres);
+	runtime·mapaccess(t, h, ak, av, &pres);
 
 	if(debug) {
 		runtime·prints("runtime.mapaccess1: map=");
@@ -838,18 +849,21 @@
 // mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
 #pragma textflag 7
 void
-runtime·mapaccess2(Hmap *h, ...)
+runtime·mapaccess2(MapType *t, Hmap *h, ...)
 {
 	byte *ak, *av, *ap;
 
-	if(h == nil)
-		runtime·panicstring("lookup in nil map");
+	if(h == nil) {
+		ak = (byte*)(&h + 1);
+		av = ak + runtime·rnd(t->key->size, Structrnd);
+		ap = av + t->elem->size;
+	} else {
+		ak = (byte*)&h + h->ko1;
+		av = (byte*)&h + h->vo1;
+		ap = (byte*)&h + h->po1;
+	}
 
-	ak = (byte*)&h + h->ko1;
-	av = (byte*)&h + h->vo1;
-	ap = (byte*)&h + h->po1;
-
-	runtime·mapaccess(h, ak, av, ap);
+	runtime·mapaccess(t, h, ak, av, ap);
 
 	if(debug) {
 		runtime·prints("runtime.mapaccess2: map=");
@@ -865,39 +879,39 @@
 }
 
 // For reflect:
-//	func mapaccess(h map, key iword) (val iword, pres bool)
+//	func mapaccess(t type, h map, key iword) (val iword, pres bool)
 // where an iword is the same word an interface value would use:
 // the actual data if it fits, or else a pointer to the data.
 void
-reflect·mapaccess(Hmap *h, uintptr key, uintptr val, bool pres)
+reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
 {
 	byte *ak, *av;
 
-	if(h == nil)
-		runtime·panicstring("lookup in nil map");
-	if(h->keysize <= sizeof(key))
+	if(t->key->size <= sizeof(key))
 		ak = (byte*)&key;
 	else
 		ak = (byte*)key;
 	val = 0;
 	pres = false;
-	if(h->valsize <= sizeof(val))
+	if(t->elem->size <= sizeof(val))
 		av = (byte*)&val;
 	else {
-		av = runtime·mal(h->valsize);
+		av = runtime·mal(t->elem->size);
 		val = (uintptr)av;
 	}
-	runtime·mapaccess(h, ak, av, &pres);
+	runtime·mapaccess(t, h, ak, av, &pres);
 	FLUSH(&val);
 	FLUSH(&pres);
 }
 
 void
-runtime·mapassign(Hmap *h, byte *ak, byte *av)
+runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
 {
 	byte *res;
 	int32 hit;
 
+	USED(t);
+
 	if(h == nil)
 		runtime·panicstring("assignment to entry in nil map");
 
@@ -931,10 +945,10 @@
 	}
 }
 
-// mapassign1(hmap *map[any]any, key any, val any);
+// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
 #pragma textflag 7
 void
-runtime·mapassign1(Hmap *h, ...)
+runtime·mapassign1(MapType *t, Hmap *h, ...)
 {
 	byte *ak, *av;
 
@@ -944,13 +958,13 @@
 	ak = (byte*)&h + h->ko2;
 	av = (byte*)&h + h->vo2;
 
-	runtime·mapassign(h, ak, av);
+	runtime·mapassign(t, h, ak, av);
 }
 
-// mapassign2(hmap *map[any]any, key any, val any, pres bool);
+// mapassign2(mapType *type, hmap *map[any]any, key any, val any, pres bool);
 #pragma textflag 7
 void
-runtime·mapassign2(Hmap *h, ...)
+runtime·mapassign2(MapType *t, Hmap *h, ...)
 {
 	byte *ak, *av, *ap;
 
@@ -964,7 +978,7 @@
 	if(*ap == false)
 		av = nil;	// delete
 
-	runtime·mapassign(h, ak, av);
+	runtime·mapassign(t, h, ak, av);
 
 	if(debug) {
 		runtime·prints("mapassign2: map=");
@@ -976,16 +990,16 @@
 }
 
 // For reflect:
-//	func mapassign(h map, key, val iword, pres bool)
+//	func mapassign(t type h map, key, val iword, pres bool)
 // where an iword is the same word an interface value would use:
 // the actual data if it fits, or else a pointer to the data.
 void
-reflect·mapassign(Hmap *h, uintptr key, uintptr val, bool pres)
+reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
 {
 	byte *ak, *av;
 
 	if(h == nil)
-		runtime·panicstring("lookup in nil map");
+		runtime·panicstring("assignment to entry in nil map");
 	if(h->keysize <= sizeof(key))
 		ak = (byte*)&key;
 	else
@@ -996,12 +1010,12 @@
 		av = (byte*)val;
 	if(!pres)
 		av = nil;
-	runtime·mapassign(h, ak, av);
+	runtime·mapassign(t, h, ak, av);
 }
 
-// mapiterinit(hmap *map[any]any, hiter *any);
+// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
 void
-runtime·mapiterinit(Hmap *h, struct hash_iter *it)
+runtime·mapiterinit(MapType*, Hmap *h, struct hash_iter *it)
 {
 	if(h == nil) {
 		it->data = nil;
@@ -1023,11 +1037,11 @@
 // For reflect:
 //	func mapiterinit(h map) (it iter)
 void
-reflect·mapiterinit(Hmap *h, struct hash_iter *it)
+reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
 {
 	it = runtime·mal(sizeof *it);
 	FLUSH(&it);
-	runtime·mapiterinit(h, it);
+	runtime·mapiterinit(t, h, it);
 }
 
 // mapiternext(hiter *any);
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 3c503e4..9719c30 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -62,6 +62,7 @@
 typedef	struct	Itab		Itab;
 typedef	struct	Eface		Eface;
 typedef	struct	Type		Type;
+typedef	struct	MapType		MapType;
 typedef	struct	Defer		Defer;
 typedef	struct	Panic		Panic;
 typedef	struct	Hmap		Hmap;
@@ -616,12 +617,12 @@
 void	runtime·procyield(uint32);
 void	runtime·osyield(void);
 
-void	runtime·mapassign(Hmap*, byte*, byte*);
-void	runtime·mapaccess(Hmap*, byte*, byte*, bool*);
+void	runtime·mapassign(MapType*, Hmap*, byte*, byte*);
+void	runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
 void	runtime·mapiternext(struct hash_iter*);
 bool	runtime·mapiterkey(struct hash_iter*, void*);
 void	runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
-Hmap*	runtime·makemap_c(Type*, Type*, int64);
+Hmap*	runtime·makemap_c(MapType*, int64);
 
 Hchan*	runtime·makechan_c(Type*, int64);
 void	runtime·chansend(Hchan*, void*, bool*);
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 1adb6dc..d406755 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -16,7 +16,6 @@
 typedef struct InterfaceType InterfaceType;
 typedef struct Method Method;
 typedef struct IMethod IMethod;
-typedef struct MapType MapType;
 typedef struct ChanType ChanType;
 typedef struct SliceType SliceType;
 typedef struct FuncType FuncType;