From 65bde087aeaad4844ea13c0064bcd4d8cc90cc03 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Aug 2011 14:56:27 -0400 Subject: [PATCH] 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 --- src/cmd/gc/builtin.c.boot | 12 ++--- src/cmd/gc/range.c | 2 +- src/cmd/gc/runtime.go | 12 ++--- src/cmd/gc/walk.c | 10 ++-- src/pkg/reflect/value.go | 12 ++--- src/pkg/runtime/hashmap.c | 106 +++++++++++++++++++++----------------- src/pkg/runtime/runtime.h | 7 +-- src/pkg/runtime/type.h | 1 - 8 files changed, 88 insertions(+), 74 deletions(-) diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index 6419873a28c..84eef6982df 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 fb33e4e4855..5ce693ae35c 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 7254f874e85..64098ab137c 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 0383e5a6a50..7a39db2d80a 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 87d12bb0b71..e40b4349100 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 179a56375b1..0c0e3e4a2de 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"); + 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 @@ 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"); + 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 @@ 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 3c503e430b5..9719c30f01c 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 1adb6dc2e73..d4067556de8 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;