aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-08-17 14:56:27 -0400
committerRuss Cox <rsc@golang.org>2011-08-17 14:56:27 -0400
commit65bde087aeaad4844ea13c0064bcd4d8cc90cc03 (patch)
tree0faa9f92e942897f77e17c163fcc24bf1306200b
parentcf79411b1deac3c416db6b0c47e6cf34cd99f37e (diff)
downloadgo-65bde087aeaad4844ea13c0064bcd4d8cc90cc03.tar.gz
go-65bde087aeaad4844ea13c0064bcd4d8cc90cc03.zip
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
-rw-r--r--src/cmd/gc/builtin.c.boot12
-rw-r--r--src/cmd/gc/range.c2
-rw-r--r--src/cmd/gc/runtime.go12
-rw-r--r--src/cmd/gc/walk.c10
-rw-r--r--src/pkg/reflect/value.go12
-rw-r--r--src/pkg/runtime/hashmap.c106
-rw-r--r--src/pkg/runtime/runtime.h7
-rw-r--r--src/pkg/runtime/type.h1
8 files changed, 88 insertions, 74 deletions
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 6419873a28..84eef6982d 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -57,12 +57,12 @@ char *runtimeimport =
"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 fb33e4e485..5ce693ae35 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -175,7 +175,7 @@ walkrange(Node *n)
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 7254f874e8..64098ab137 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -80,12 +80,12 @@ func ifacethash(i1 any) (ret uint32)
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 0383e5a6a5..7a39db2d80 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -604,7 +604,7 @@ walkexpr(Node **np, NodeList **init)
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 @@ walkexpr(Node **np, NodeList **init)
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 @@ walkexpr(Node **np, NodeList **init)
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 @@ walkexpr(Node **np, NodeList **init)
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 @@ convas(Node *n, NodeList **init)
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 87d12bb0b7..e40b434910 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -977,7 +977,7 @@ func (v Value) MapIndex(key Value) Value {
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 @@ func (v Value) MapKeys() []Value {
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 @@ func (v Value) SetMapIndex(key, val Value) {
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 chansend(ch iword, val iword, nb bool) bool
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 179a56375b..0c0e3e4a2d 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -690,13 +690,17 @@ hash_indirect(Hmap *h, void *p)
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 @@ runtime·makemap_c(Type *key, Type *val, int64 hint)
// 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 @@ runtime·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
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 @@ runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
// 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");
-
- ak = (byte*)&h + h->ko1;
- av = (byte*)&h + h->vo1;
+ 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;
+ }
- runtime·mapaccess(h, ak, av, &pres);
+ runtime·mapaccess(t, h, ak, av, &pres);
if(debug) {
runtime·prints("runtime.mapaccess1: map=");
@@ -838,18 +849,21 @@ runtime·mapaccess1(Hmap *h, ...)
// 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");
-
- ak = (byte*)&h + h->ko1;
- av = (byte*)&h + h->vo1;
- ap = (byte*)&h + h->po1;
+ 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;
+ }
- runtime·mapaccess(h, ak, av, ap);
+ runtime·mapaccess(t, h, ak, av, ap);
if(debug) {
runtime·prints("runtime.mapaccess2: map=");
@@ -865,39 +879,39 @@ runtime·mapaccess2(Hmap *h, ...)
}
// 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 @@ runtime·mapassign(Hmap *h, byte *ak, byte *av)
}
}
-// 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 @@ runtime·mapassign1(Hmap *h, ...)
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 @@ runtime·mapassign2(Hmap *h, ...)
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 @@ runtime·mapassign2(Hmap *h, ...)
}
// 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 @@ reflect·mapassign(Hmap *h, uintptr key, uintptr val, bool pres)
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 @@ runtime·mapiterinit(Hmap *h, struct hash_iter *it)
// 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 3c503e430b..9719c30f01 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -62,6 +62,7 @@ typedef struct Iface Iface;
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 @@ int32 runtime·gomaxprocsfunc(int32 n);
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 1adb6dc2e7..d4067556de 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -16,7 +16,6 @@ typedef struct UncommonType UncommonType;
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;