mirror of
https://github.com/golang/go
synced 2024-11-21 15:34:45 -07:00
runtime: prep for type-specific algorithms
Equality on structs will require arbitrary code for type equality, so change algorithm in type data from uint8 to table pointer. In the process, trim top-level map structure from 104/80 bytes (64-bit/32-bit) to 24/12. Equality on structs will require being able to call code generated by the Go compiler, and C code has no way to access Go return values, so change the hash and equal algorithm functions to take a pointer to a result instead of returning the result. R=ken CC=golang-dev https://golang.org/cl/5453043
This commit is contained in:
parent
263c955f2f
commit
b9ccd077dc
@ -1,116 +1,116 @@
|
||||
char *runtimeimport =
|
||||
"package runtime\n"
|
||||
"import runtime \"runtime\"\n"
|
||||
"func @\"\".new (typ *byte) *any\n"
|
||||
"func @\"\".panicindex ()\n"
|
||||
"func @\"\".panicslice ()\n"
|
||||
"func @\"\".throwreturn ()\n"
|
||||
"func @\"\".throwinit ()\n"
|
||||
"func @\"\".panicwrap (? string, ? string, ? string)\n"
|
||||
"func @\"\".panic (? interface { })\n"
|
||||
"func @\"\".recover (? *int32) interface { }\n"
|
||||
"func @\"\".printbool (? bool)\n"
|
||||
"func @\"\".printfloat (? float64)\n"
|
||||
"func @\"\".printint (? int64)\n"
|
||||
"func @\"\".printuint (? uint64)\n"
|
||||
"func @\"\".printcomplex (? complex128)\n"
|
||||
"func @\"\".printstring (? string)\n"
|
||||
"func @\"\".printpointer (? any)\n"
|
||||
"func @\"\".printiface (? any)\n"
|
||||
"func @\"\".printeface (? any)\n"
|
||||
"func @\"\".printslice (? any)\n"
|
||||
"func @\"\".printnl ()\n"
|
||||
"func @\"\".printsp ()\n"
|
||||
"func @\"\".goprintf ()\n"
|
||||
"func @\"\".concatstring ()\n"
|
||||
"func @\"\".append ()\n"
|
||||
"func @\"\".appendslice (typ *byte, x any, y []any) any\n"
|
||||
"func @\"\".appendstr (typ *byte, x []byte, y string) []byte\n"
|
||||
"func @\"\".cmpstring (? string, ? string) int\n"
|
||||
"func @\"\".slicestring (? string, ? int, ? int) string\n"
|
||||
"func @\"\".slicestring1 (? string, ? int) string\n"
|
||||
"func @\"\".intstring (? int64) string\n"
|
||||
"func @\"\".slicebytetostring (? []byte) string\n"
|
||||
"func @\"\".slicerunetostring (? []rune) string\n"
|
||||
"func @\"\".stringtoslicebyte (? string) []byte\n"
|
||||
"func @\"\".stringtoslicerune (? string) []rune\n"
|
||||
"func @\"\".stringiter (? string, ? int) int\n"
|
||||
"func @\"\".stringiter2 (? string, ? int) (retk int, retv rune)\n"
|
||||
"func @\"\".slicecopy (to any, fr any, wid uint32) int\n"
|
||||
"func @\"\".slicestringcopy (to any, fr any) int\n"
|
||||
"func @\"\".convI2E (elem any) any\n"
|
||||
"func @\"\".convI2I (typ *byte, elem any) any\n"
|
||||
"func @\"\".convT2E (typ *byte, elem any) any\n"
|
||||
"func @\"\".convT2I (typ *byte, typ2 *byte, elem any) any\n"
|
||||
"func @\"\".assertE2E (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2E2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertE2I (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2I2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertE2T (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2T2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2E (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2E2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2I (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2I2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2T (typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2T2 (typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".ifaceeq (i1 any, i2 any) bool\n"
|
||||
"func @\"\".efaceeq (i1 any, i2 any) bool\n"
|
||||
"func @\"\".ifacethash (i1 any) uint32\n"
|
||||
"func @\"\".efacethash (i1 any) uint32\n"
|
||||
"func @\"\".makemap (mapType *byte, hint int64) map[any] any\n"
|
||||
"func @\"\".mapaccess1 (mapType *byte, hmap map[any] any, key any) any\n"
|
||||
"func @\"\".mapaccess2 (mapType *byte, hmap map[any] any, key any) (val any, pres bool)\n"
|
||||
"func @\"\".mapassign1 (mapType *byte, hmap map[any] any, key any, val any)\n"
|
||||
"func @\"\".mapassign2 (mapType *byte, hmap map[any] any, key any, val any, pres bool)\n"
|
||||
"func @\"\".mapiterinit (mapType *byte, hmap map[any] any, hiter *any)\n"
|
||||
"func @\"\".mapdelete (mapType *byte, hmap map[any] any, key any)\n"
|
||||
"func @\"\".mapiternext (hiter *any)\n"
|
||||
"func @\"\".mapiter1 (hiter *any) any\n"
|
||||
"func @\"\".mapiter2 (hiter *any) (key any, val any)\n"
|
||||
"func @\"\".makechan (chanType *byte, hint int64) chan any\n"
|
||||
"func @\"\".chanrecv1 (chanType *byte, hchan <-chan any) any\n"
|
||||
"func @\"\".chanrecv2 (chanType *byte, hchan <-chan any) (elem any, received bool)\n"
|
||||
"func @\"\".chansend1 (chanType *byte, hchan chan<- any, elem any)\n"
|
||||
"func @\"\".closechan (hchan any)\n"
|
||||
"func @\"\".selectnbsend (chanType *byte, hchan chan<- any, elem any) bool\n"
|
||||
"func @\"\".selectnbrecv (chanType *byte, elem *any, hchan <-chan any) bool\n"
|
||||
"func @\"\".selectnbrecv2 (chanType *byte, elem *any, received *bool, hchan <-chan any) bool\n"
|
||||
"func @\"\".newselect (size int) *byte\n"
|
||||
"func @\"\".selectsend (sel *byte, hchan chan<- any, elem *any) bool\n"
|
||||
"func @\"\".selectrecv (sel *byte, hchan <-chan any, elem *any) bool\n"
|
||||
"func @\"\".selectrecv2 (sel *byte, hchan <-chan any, elem *any, received *bool) bool\n"
|
||||
"func @\"\".selectdefault (sel *byte) bool\n"
|
||||
"func @\"\".selectgo (sel *byte)\n"
|
||||
"func @\"\".block ()\n"
|
||||
"func @\"\".makeslice (typ *byte, nel int64, cap int64) []any\n"
|
||||
"func @\"\".growslice (typ *byte, old []any, n int64) []any\n"
|
||||
"func @\"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
|
||||
"func @\"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
|
||||
"func @\"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
|
||||
"func @\"\".closure ()\n"
|
||||
"func @\"\".int64div (? int64, ? int64) int64\n"
|
||||
"func @\"\".uint64div (? uint64, ? uint64) uint64\n"
|
||||
"func @\"\".int64mod (? int64, ? int64) int64\n"
|
||||
"func @\"\".uint64mod (? uint64, ? uint64) uint64\n"
|
||||
"func @\"\".float64toint64 (? float64) int64\n"
|
||||
"func @\"\".float64touint64 (? float64) uint64\n"
|
||||
"func @\"\".int64tofloat64 (? int64) float64\n"
|
||||
"func @\"\".uint64tofloat64 (? uint64) float64\n"
|
||||
"func @\"\".complex128div (num complex128, den complex128) complex128\n"
|
||||
"func @\"\".new(typ *byte) *any\n"
|
||||
"func @\"\".panicindex()\n"
|
||||
"func @\"\".panicslice()\n"
|
||||
"func @\"\".throwreturn()\n"
|
||||
"func @\"\".throwinit()\n"
|
||||
"func @\"\".panicwrap(? string, ? string, ? string)\n"
|
||||
"func @\"\".panic(? interface {})\n"
|
||||
"func @\"\".recover(? *int32) interface {}\n"
|
||||
"func @\"\".printbool(? bool)\n"
|
||||
"func @\"\".printfloat(? float64)\n"
|
||||
"func @\"\".printint(? int64)\n"
|
||||
"func @\"\".printuint(? uint64)\n"
|
||||
"func @\"\".printcomplex(? complex128)\n"
|
||||
"func @\"\".printstring(? string)\n"
|
||||
"func @\"\".printpointer(? any)\n"
|
||||
"func @\"\".printiface(? any)\n"
|
||||
"func @\"\".printeface(? any)\n"
|
||||
"func @\"\".printslice(? any)\n"
|
||||
"func @\"\".printnl()\n"
|
||||
"func @\"\".printsp()\n"
|
||||
"func @\"\".goprintf()\n"
|
||||
"func @\"\".concatstring()\n"
|
||||
"func @\"\".append()\n"
|
||||
"func @\"\".appendslice(typ *byte, x any, y []any) any\n"
|
||||
"func @\"\".appendstr(typ *byte, x []byte, y string) []byte\n"
|
||||
"func @\"\".cmpstring(? string, ? string) int\n"
|
||||
"func @\"\".slicestring(? string, ? int, ? int) string\n"
|
||||
"func @\"\".slicestring1(? string, ? int) string\n"
|
||||
"func @\"\".intstring(? int64) string\n"
|
||||
"func @\"\".slicebytetostring(? []byte) string\n"
|
||||
"func @\"\".slicerunetostring(? []rune) string\n"
|
||||
"func @\"\".stringtoslicebyte(? string) []byte\n"
|
||||
"func @\"\".stringtoslicerune(? string) []rune\n"
|
||||
"func @\"\".stringiter(? string, ? int) int\n"
|
||||
"func @\"\".stringiter2(? string, ? int) (retk int, retv rune)\n"
|
||||
"func @\"\".copy(to any, fr any, wid uint32) int\n"
|
||||
"func @\"\".slicestringcopy(to any, fr any) int\n"
|
||||
"func @\"\".convI2E(elem any) any\n"
|
||||
"func @\"\".convI2I(typ *byte, elem any) any\n"
|
||||
"func @\"\".convT2E(typ *byte, elem any) any\n"
|
||||
"func @\"\".convT2I(typ *byte, typ2 *byte, elem any) any\n"
|
||||
"func @\"\".assertE2E(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2E2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertE2I(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2I2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertE2T(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertE2T2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2E(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2E2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2I(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2I2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".assertI2T(typ *byte, iface any) any\n"
|
||||
"func @\"\".assertI2T2(typ *byte, iface any) (ret any, ok bool)\n"
|
||||
"func @\"\".ifaceeq(i1 any, i2 any) bool\n"
|
||||
"func @\"\".efaceeq(i1 any, i2 any) bool\n"
|
||||
"func @\"\".ifacethash(i1 any) uint32\n"
|
||||
"func @\"\".efacethash(i1 any) uint32\n"
|
||||
"func @\"\".makemap(mapType *byte, hint int64) map[any]any\n"
|
||||
"func @\"\".mapaccess1(mapType *byte, hmap map[any]any, key any) any\n"
|
||||
"func @\"\".mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)\n"
|
||||
"func @\"\".mapassign1(mapType *byte, hmap map[any]any, key any, val any)\n"
|
||||
"func @\"\".mapassign2(mapType *byte, hmap map[any]any, key any, val any, pres bool)\n"
|
||||
"func @\"\".mapiterinit(mapType *byte, hmap map[any]any, hiter *any)\n"
|
||||
"func @\"\".mapdelete(mapType *byte, hmap map[any]any, key any)\n"
|
||||
"func @\"\".mapiternext(hiter *any)\n"
|
||||
"func @\"\".mapiter1(hiter *any) any\n"
|
||||
"func @\"\".mapiter2(hiter *any) (key any, val any)\n"
|
||||
"func @\"\".makechan(chanType *byte, hint int64) chan any\n"
|
||||
"func @\"\".chanrecv1(chanType *byte, hchan <-chan any) any\n"
|
||||
"func @\"\".chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool)\n"
|
||||
"func @\"\".chansend1(chanType *byte, hchan chan<- any, elem any)\n"
|
||||
"func @\"\".closechan(hchan any)\n"
|
||||
"func @\"\".selectnbsend(chanType *byte, hchan chan<- any, elem any) bool\n"
|
||||
"func @\"\".selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool\n"
|
||||
"func @\"\".selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool\n"
|
||||
"func @\"\".newselect(size int) *byte\n"
|
||||
"func @\"\".selectsend(sel *byte, hchan chan<- any, elem *any) bool\n"
|
||||
"func @\"\".selectrecv(sel *byte, hchan <-chan any, elem *any) bool\n"
|
||||
"func @\"\".selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) bool\n"
|
||||
"func @\"\".selectdefault(sel *byte) bool\n"
|
||||
"func @\"\".selectgo(sel *byte)\n"
|
||||
"func @\"\".block()\n"
|
||||
"func @\"\".makeslice(typ *byte, nel int64, cap int64) []any\n"
|
||||
"func @\"\".growslice(typ *byte, old []any, n int64) []any\n"
|
||||
"func @\"\".sliceslice1(old []any, lb uint64, width uint64) []any\n"
|
||||
"func @\"\".sliceslice(old []any, lb uint64, hb uint64, width uint64) []any\n"
|
||||
"func @\"\".slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
|
||||
"func @\"\".closure()\n"
|
||||
"func @\"\".int64div(? int64, ? int64) int64\n"
|
||||
"func @\"\".uint64div(? uint64, ? uint64) uint64\n"
|
||||
"func @\"\".int64mod(? int64, ? int64) int64\n"
|
||||
"func @\"\".uint64mod(? uint64, ? uint64) uint64\n"
|
||||
"func @\"\".float64toint64(? float64) int64\n"
|
||||
"func @\"\".float64touint64(? float64) uint64\n"
|
||||
"func @\"\".int64tofloat64(? int64) float64\n"
|
||||
"func @\"\".uint64tofloat64(? uint64) float64\n"
|
||||
"func @\"\".complex128div(num complex128, den complex128) complex128\n"
|
||||
"\n"
|
||||
"$$\n";
|
||||
char *unsafeimport =
|
||||
"package unsafe\n"
|
||||
"import runtime \"runtime\"\n"
|
||||
"type @\"\".Pointer uintptr\n"
|
||||
"func @\"\".Offsetof (? any) uintptr\n"
|
||||
"func @\"\".Sizeof (? any) uintptr\n"
|
||||
"func @\"\".Alignof (? any) uintptr\n"
|
||||
"func @\"\".Typeof (i interface { }) interface { }\n"
|
||||
"func @\"\".Reflect (i interface { }) (typ interface { }, addr @\"\".Pointer)\n"
|
||||
"func @\"\".Unreflect (typ interface { }, addr @\"\".Pointer) interface { }\n"
|
||||
"func @\"\".New (typ interface { }) @\"\".Pointer\n"
|
||||
"func @\"\".NewArray (typ interface { }, n int) @\"\".Pointer\n"
|
||||
"func @\"\".Offsetof(? any) uintptr\n"
|
||||
"func @\"\".Sizeof(? any) uintptr\n"
|
||||
"func @\"\".Alignof(? any) uintptr\n"
|
||||
"func @\"\".Typeof(i interface {}) interface {}\n"
|
||||
"func @\"\".Reflect(i interface {}) (typ interface {}, addr @\"\".Pointer)\n"
|
||||
"func @\"\".Unreflect(typ interface {}, addr @\"\".Pointer) interface {}\n"
|
||||
"func @\"\".New(typ interface {}) @\"\".Pointer\n"
|
||||
"func @\"\".NewArray(typ interface {}, n int) @\"\".Pointer\n"
|
||||
"\n"
|
||||
"$$\n";
|
||||
|
@ -72,35 +72,6 @@ struct Strlit
|
||||
char s[3]; // variable
|
||||
};
|
||||
|
||||
/*
|
||||
* note this is the runtime representation
|
||||
* of hashmap iterator. it is probably
|
||||
* insafe to use it this way, but it puts
|
||||
* all the changes in one place.
|
||||
* only flag is referenced from go.
|
||||
* actual placement does not matter as long
|
||||
* as the size is >= actual size.
|
||||
*/
|
||||
typedef struct Hiter Hiter;
|
||||
struct Hiter
|
||||
{
|
||||
uchar data[8]; // return val from next
|
||||
int32 elemsize; // size of elements in table
|
||||
int32 changes; // number of changes observed last time
|
||||
int32 i; // stack pointer in subtable_state
|
||||
int32 cycled; // actually a bool but pad for next field, a pointer
|
||||
uchar last[8]; // last hash value returned
|
||||
uchar cycle[8]; // the value where we started and will stop
|
||||
uchar h[8]; // the hash table
|
||||
struct
|
||||
{
|
||||
uchar sub[8]; // pointer into subtable
|
||||
uchar start[8]; // pointer into start of subtable
|
||||
uchar end[8]; // pointer into end of subtable
|
||||
uchar pad[8];
|
||||
} sub[4];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Mpscale = 29, // safely smaller than bits in a long
|
||||
|
@ -167,7 +167,9 @@ walkrange(Node *n)
|
||||
case TMAP:
|
||||
th = typ(TARRAY);
|
||||
th->type = ptrto(types[TUINT8]);
|
||||
th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
|
||||
// see ../../pkg/runtime/hashmap.h:/hash_iter
|
||||
// Size in words.
|
||||
th->bound = 5 + 4*3 + 4*4/widthptr;
|
||||
hit = temp(th);
|
||||
|
||||
fn = syslook("mapiterinit", 1);
|
||||
|
@ -553,10 +553,15 @@ haspointers(Type *t)
|
||||
static int
|
||||
dcommontype(Sym *s, int ot, Type *t)
|
||||
{
|
||||
int i;
|
||||
int i, sizeofAlg;
|
||||
Sym *sptr;
|
||||
static Sym *algarray;
|
||||
char *p;
|
||||
|
||||
sizeofAlg = 4*widthptr;
|
||||
if(algarray == nil)
|
||||
algarray = pkglookup("algarray", runtimepkg);
|
||||
|
||||
dowidth(t);
|
||||
|
||||
if(t->sym != nil && !isptr[t->etype])
|
||||
@ -586,7 +591,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
// }
|
||||
ot = duintptr(s, ot, t->width);
|
||||
ot = duint32(s, ot, typehash(t));
|
||||
ot = duint8(s, ot, algtype(t));
|
||||
ot = duint8(s, ot, 0); // unused
|
||||
ot = duint8(s, ot, t->align); // align
|
||||
ot = duint8(s, ot, t->align); // fieldAlign
|
||||
i = kinds[t->etype];
|
||||
@ -595,6 +600,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
if(!haspointers(t))
|
||||
i |= KindNoPointers;
|
||||
ot = duint8(s, ot, i); // kind
|
||||
ot = dsymptr(s, ot, algarray, algtype(t)*sizeofAlg);
|
||||
p = smprint("%-uT", t);
|
||||
//print("dcommontype: %s\n", p);
|
||||
ot = dgostringptr(s, ot, p); // string
|
||||
|
@ -52,7 +52,7 @@ func stringtoslicebyte(string) []byte
|
||||
func stringtoslicerune(string) []rune
|
||||
func stringiter(string, int) int
|
||||
func stringiter2(string, int) (retk int, retv rune)
|
||||
func slicecopy(to any, fr any, wid uint32) int
|
||||
func copy(to any, fr any, wid uint32) int
|
||||
func slicestringcopy(to any, fr any) int
|
||||
|
||||
// interface conversions
|
||||
|
@ -1078,7 +1078,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
if(n->right->type->etype == TSTRING)
|
||||
fn = syslook("slicestringcopy", 1);
|
||||
else
|
||||
fn = syslook("slicecopy", 1);
|
||||
fn = syslook("copy", 1);
|
||||
argtype(fn, n->left->type);
|
||||
argtype(fn, n->right->type);
|
||||
n = mkcall1(fn, n->type, init,
|
||||
|
@ -775,7 +775,7 @@ enum {
|
||||
KindNoPointers = 1<<7,
|
||||
|
||||
// size of Type interface header + CommonType structure.
|
||||
CommonSize = 2*PtrSize+ 4*PtrSize + 8,
|
||||
CommonSize = 2*PtrSize+ 5*PtrSize + 8,
|
||||
};
|
||||
|
||||
static Reloc*
|
||||
|
@ -241,10 +241,11 @@ const (
|
||||
type commonType struct {
|
||||
size uintptr
|
||||
hash uint32
|
||||
alg uint8
|
||||
_ uint8
|
||||
align uint8
|
||||
fieldAlign uint8
|
||||
kind uint8
|
||||
alg *uintptr
|
||||
string *string
|
||||
*uncommonType
|
||||
ptrToThis *runtime.Type
|
||||
|
@ -63,6 +63,7 @@ OFILES_arm=\
|
||||
vlrt.$O\
|
||||
|
||||
OFILES=\
|
||||
alg.$O\
|
||||
asm.$O\
|
||||
atomic.$O\
|
||||
cgocall.$O\
|
||||
|
345
src/pkg/runtime/alg.c
Normal file
345
src/pkg/runtime/alg.c
Normal file
@ -0,0 +1,345 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "runtime.h"
|
||||
|
||||
/*
|
||||
* map and chan helpers for
|
||||
* dealing with unknown types
|
||||
*/
|
||||
void
|
||||
runtime·memhash(uintptr *h, uintptr s, void *a)
|
||||
{
|
||||
byte *b;
|
||||
uintptr hash;
|
||||
|
||||
b = a;
|
||||
if(sizeof(hash) == 4)
|
||||
hash = 2860486313U;
|
||||
else
|
||||
hash = 33054211828000289ULL;
|
||||
while(s > 0) {
|
||||
if(sizeof(hash) == 4)
|
||||
hash = (hash ^ *b) * 3267000013UL;
|
||||
else
|
||||
hash = (hash ^ *b) * 23344194077549503ULL;
|
||||
b++;
|
||||
s--;
|
||||
}
|
||||
*h ^= hash;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
byte *ba, *bb, *aend;
|
||||
|
||||
if(a == b) {
|
||||
*eq = 1;
|
||||
return;
|
||||
}
|
||||
ba = a;
|
||||
bb = b;
|
||||
aend = ba+s;
|
||||
while(ba != aend) {
|
||||
if(*ba != *bb) {
|
||||
*eq = 0;
|
||||
return;
|
||||
}
|
||||
ba++;
|
||||
bb++;
|
||||
}
|
||||
*eq = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memprint(uintptr s, void *a)
|
||||
{
|
||||
uint64 v;
|
||||
|
||||
v = 0xbadb00b;
|
||||
switch(s) {
|
||||
case 1:
|
||||
v = *(uint8*)a;
|
||||
break;
|
||||
case 2:
|
||||
v = *(uint16*)a;
|
||||
break;
|
||||
case 4:
|
||||
v = *(uintptr*)a;
|
||||
break;
|
||||
case 8:
|
||||
v = *(uint64*)a;
|
||||
break;
|
||||
}
|
||||
runtime·printint(v);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy(uintptr s, void *a, void *b)
|
||||
{
|
||||
if(b == nil) {
|
||||
runtime·memclr(a, s);
|
||||
return;
|
||||
}
|
||||
runtime·memmove(a, b, s);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal8(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = *(uint8*)a == *(uint8*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy8(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*(uint8*)a = 0;
|
||||
return;
|
||||
}
|
||||
*(uint8*)a = *(uint8*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal16(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = *(uint16*)a == *(uint16*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy16(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*(uint16*)a = 0;
|
||||
return;
|
||||
}
|
||||
*(uint16*)a = *(uint16*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal32(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = *(uint32*)a == *(uint32*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy32(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*(uint32*)a = 0;
|
||||
return;
|
||||
}
|
||||
*(uint32*)a = *(uint32*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal64(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = *(uint64*)a == *(uint64*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy64(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*(uint64*)a = 0;
|
||||
return;
|
||||
}
|
||||
*(uint64*)a = *(uint64*)b;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memequal128(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1];
|
||||
}
|
||||
|
||||
void
|
||||
runtime·memcopy128(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
((uint64*)a)[0] = 0;
|
||||
((uint64*)a)[1] = 0;
|
||||
return;
|
||||
}
|
||||
((uint64*)a)[0] = ((uint64*)b)[0];
|
||||
((uint64*)a)[1] = ((uint64*)b)[1];
|
||||
}
|
||||
|
||||
void
|
||||
runtime·slicecopy(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
((Slice*)a)->array = 0;
|
||||
((Slice*)a)->len = 0;
|
||||
((Slice*)a)->cap = 0;
|
||||
return;
|
||||
}
|
||||
((Slice*)a)->array = ((Slice*)b)->array;
|
||||
((Slice*)a)->len = ((Slice*)b)->len;
|
||||
((Slice*)a)->cap = ((Slice*)b)->cap;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·strhash(uintptr *h, uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·memhash(h, ((String*)a)->len, ((String*)a)->str);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·strequal(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
int32 alen;
|
||||
|
||||
USED(s);
|
||||
alen = ((String*)a)->len;
|
||||
if(alen != ((String*)b)->len) {
|
||||
*eq = false;
|
||||
return;
|
||||
}
|
||||
runtime·memequal(eq, alen, ((String*)a)->str, ((String*)b)->str);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·strprint(uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printstring(*(String*)a);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·strcopy(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
((String*)a)->str = 0;
|
||||
((String*)a)->len = 0;
|
||||
return;
|
||||
}
|
||||
((String*)a)->str = ((String*)b)->str;
|
||||
((String*)a)->len = ((String*)b)->len;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·interhash(uintptr *h, uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
*h ^= runtime·ifacehash(*(Iface*)a);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·interprint(uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printiface(*(Iface*)a);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·interequal(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·intercopy(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
((Iface*)a)->tab = 0;
|
||||
((Iface*)a)->data = 0;
|
||||
return;
|
||||
}
|
||||
((Iface*)a)->tab = ((Iface*)b)->tab;
|
||||
((Iface*)a)->data = ((Iface*)b)->data;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·nilinterhash(uintptr *h, uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
*h ^= runtime·efacehash(*(Eface*)a);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·nilinterprint(uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printeface(*(Eface*)a);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
*eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·nilintercopy(uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
((Eface*)a)->type = 0;
|
||||
((Eface*)a)->data = 0;
|
||||
return;
|
||||
}
|
||||
((Eface*)a)->type = ((Eface*)b)->type;
|
||||
((Eface*)a)->data = ((Eface*)b)->data;
|
||||
}
|
||||
|
||||
void
|
||||
runtime·nohash(uintptr *h, uintptr s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
USED(h);
|
||||
runtime·panicstring("hash of unhashable type");
|
||||
}
|
||||
|
||||
void
|
||||
runtime·noequal(bool *eq, uintptr s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
USED(b);
|
||||
USED(eq);
|
||||
runtime·panicstring("comparing uncomparable types");
|
||||
}
|
||||
|
||||
Alg
|
||||
runtime·algarray[] =
|
||||
{
|
||||
[AMEM] { runtime·memhash, runtime·memequal, runtime·memprint, runtime·memcopy },
|
||||
[ANOEQ] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy },
|
||||
[ASTRING] { runtime·strhash, runtime·strequal, runtime·strprint, runtime·strcopy },
|
||||
[AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
|
||||
[ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
|
||||
[ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
|
||||
[AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
|
||||
[AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
|
||||
[AMEM32] { runtime·memhash, runtime·memequal32, runtime·memprint, runtime·memcopy32 },
|
||||
[AMEM64] { runtime·memhash, runtime·memequal64, runtime·memprint, runtime·memcopy64 },
|
||||
[AMEM128] { runtime·memhash, runtime·memequal128, runtime·memprint, runtime·memcopy128 },
|
||||
[ANOEQ8] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy8 },
|
||||
[ANOEQ16] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy16 },
|
||||
[ANOEQ32] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy32 },
|
||||
[ANOEQ64] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy64 },
|
||||
[ANOEQ128] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy128 },
|
||||
};
|
||||
|
@ -92,11 +92,6 @@ runtime·makechan_c(ChanType *t, int64 hint)
|
||||
if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size))
|
||||
runtime·panicstring("makechan: size out of range");
|
||||
|
||||
if(elem->alg >= nelem(runtime·algarray)) {
|
||||
runtime·printf("chan(alg=%d)\n", elem->alg);
|
||||
runtime·throw("runtime.makechan: unsupported elem type");
|
||||
}
|
||||
|
||||
// calculate rounded size of Hchan
|
||||
n = sizeof(*c);
|
||||
while(n & MAXALIGN)
|
||||
@ -105,12 +100,12 @@ runtime·makechan_c(ChanType *t, int64 hint)
|
||||
// allocate memory in one call
|
||||
c = (Hchan*)runtime·mal(n + hint*elem->size);
|
||||
c->elemsize = elem->size;
|
||||
c->elemalg = &runtime·algarray[elem->alg];
|
||||
c->elemalg = elem->alg;
|
||||
c->elemalign = elem->align;
|
||||
c->dataqsiz = hint;
|
||||
|
||||
if(debug)
|
||||
runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
|
||||
runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%d\n",
|
||||
c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz);
|
||||
|
||||
return c;
|
||||
|
@ -6,41 +6,14 @@
|
||||
#include "hashmap.h"
|
||||
#include "type.h"
|
||||
|
||||
/* Return a pointer to the struct/union of type "type"
|
||||
whose "field" field is addressed by pointer "p". */
|
||||
|
||||
struct Hmap { /* a hash table; initialize with hash_init() */
|
||||
uint32 count; /* elements in table - must be first */
|
||||
|
||||
uint8 datasize; /* amount of data to store in entry */
|
||||
uint8 max_power; /* max power of 2 to create sub-tables */
|
||||
uint8 max_probes; /* max entries to probe before rehashing */
|
||||
uint8 indirectval; /* storing pointers to values */
|
||||
uint8 indirectval; /* storing pointers to values */
|
||||
uint8 valoff; /* offset of value in key+value data block */
|
||||
int32 changes; /* inc'ed whenever a subtable is created/grown */
|
||||
hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */
|
||||
uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */
|
||||
void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */
|
||||
struct hash_subtable *st; /* first-level table */
|
||||
|
||||
uint32 keysize;
|
||||
uint32 valsize;
|
||||
uint32 datavo;
|
||||
|
||||
// three sets of offsets: the digit counts how many
|
||||
// of key, value are passed as inputs:
|
||||
// 0 = func() (key, value)
|
||||
// 1 = func(key) (value)
|
||||
// 2 = func(key, value)
|
||||
uint32 ko0;
|
||||
uint32 vo0;
|
||||
uint32 ko1;
|
||||
uint32 vo1;
|
||||
uint32 po1;
|
||||
uint32 ko2;
|
||||
uint32 vo2;
|
||||
uint32 po2;
|
||||
Alg* keyalg;
|
||||
Alg* valalg;
|
||||
};
|
||||
|
||||
struct hash_entry {
|
||||
@ -58,7 +31,7 @@ struct hash_subtable {
|
||||
struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
|
||||
};
|
||||
|
||||
#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y)))
|
||||
#define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key->size, (x), (y)), (eq))
|
||||
|
||||
#define HASH_REHASH 0x2 /* an internal flag */
|
||||
/* the number of bits used is stored in the flags word too */
|
||||
@ -79,6 +52,7 @@ struct hash_subtable {
|
||||
#define HASH_OFFSET(base, byte_offset) \
|
||||
((struct hash_entry *) (((byte *) (base)) + (byte_offset)))
|
||||
|
||||
#define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */
|
||||
|
||||
/* return a hash layer with 2**power empty entries */
|
||||
static struct hash_subtable *
|
||||
@ -87,8 +61,8 @@ hash_subtable_new (Hmap *h, int32 power, int32 used)
|
||||
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
int32 bytes = elemsize << power;
|
||||
struct hash_subtable *st;
|
||||
int32 limit_bytes = h->max_probes * elemsize;
|
||||
int32 max_probes = h->max_probes;
|
||||
int32 limit_bytes = HASH_MAX_PROBES * elemsize;
|
||||
int32 max_probes = HASH_MAX_PROBES;
|
||||
|
||||
if (bytes < limit_bytes) {
|
||||
limit_bytes = bytes;
|
||||
@ -127,12 +101,7 @@ init_sizes (int64 hint, int32 *init_power, int32 *max_power)
|
||||
}
|
||||
|
||||
static void
|
||||
hash_init (Hmap *h,
|
||||
int32 datasize,
|
||||
hash_hash_t (*data_hash) (uint32, void *),
|
||||
uint32 (*data_eq) (uint32, void *, void *),
|
||||
void (*data_del) (uint32, void *, void *),
|
||||
int64 hint)
|
||||
hash_init (Hmap *h, int32 datasize, int64 hint)
|
||||
{
|
||||
int32 init_power;
|
||||
int32 max_power;
|
||||
@ -143,15 +112,11 @@ hash_init (Hmap *h,
|
||||
init_sizes (hint, &init_power, &max_power);
|
||||
h->datasize = datasize;
|
||||
h->max_power = max_power;
|
||||
h->max_probes = 15;
|
||||
assert (h->datasize == datasize);
|
||||
assert (h->max_power == max_power);
|
||||
assert (sizeof (void *) <= h->datasize || h->max_power == 255);
|
||||
h->count = 0;
|
||||
h->changes = 0;
|
||||
h->data_hash = data_hash;
|
||||
h->data_eq = data_eq;
|
||||
h->data_del = data_del;
|
||||
h->st = hash_subtable_new (h, init_power, 0);
|
||||
}
|
||||
|
||||
@ -199,11 +164,11 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
|
||||
}
|
||||
|
||||
static int32
|
||||
hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
hash_insert_internal (MapType*, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
Hmap *h, void *data, void **pres);
|
||||
|
||||
static void
|
||||
hash_conv (Hmap *h,
|
||||
hash_conv (MapType *t, Hmap *h,
|
||||
struct hash_subtable *st, int32 flags,
|
||||
hash_hash_t hash,
|
||||
struct hash_entry *e)
|
||||
@ -238,13 +203,13 @@ hash_conv (Hmap *h,
|
||||
(ne <= st->last && (e_hash = ne->hash) != HASH_NIL &&
|
||||
(e_hash & prefix_mask) == current)) {
|
||||
struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
|
||||
int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
|
||||
int32 rc = hash_insert_internal (t, &new_st, new_flags, e->hash, h, e->data, &dummy_result);
|
||||
assert (rc == 0);
|
||||
memcpy(dummy_result, e->data, h->datasize);
|
||||
e = ne;
|
||||
while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
|
||||
assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
|
||||
rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
|
||||
rc = hash_insert_internal (t, &new_st, new_flags, e_hash, h, e->data, &dummy_result);
|
||||
assert (rc == 0);
|
||||
memcpy(dummy_result, e->data, h->datasize);
|
||||
e = HASH_OFFSET (e, elemsize);
|
||||
@ -266,7 +231,7 @@ hash_conv (Hmap *h,
|
||||
}
|
||||
|
||||
static void
|
||||
hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
|
||||
hash_grow (MapType *t, Hmap *h, struct hash_subtable **pst, int32 flags)
|
||||
{
|
||||
struct hash_subtable *old_st = *pst;
|
||||
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
@ -280,7 +245,7 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
|
||||
for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) {
|
||||
hash_hash_t hash = e->hash;
|
||||
if (hash != HASH_NIL) {
|
||||
int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
|
||||
int32 rc = hash_insert_internal (t, pst, flags, e->hash, h, e->data, &dummy_result);
|
||||
assert (rc == 0);
|
||||
memcpy(dummy_result, e->data, h->datasize);
|
||||
used++;
|
||||
@ -290,16 +255,20 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
|
||||
}
|
||||
|
||||
static int32
|
||||
hash_lookup (Hmap *h, void *data, void **pres)
|
||||
hash_lookup (MapType *t, Hmap *h, void *data, void **pres)
|
||||
{
|
||||
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
|
||||
hash_hash_t hash;
|
||||
struct hash_subtable *st = h->st;
|
||||
int32 used = 0;
|
||||
hash_hash_t e_hash;
|
||||
struct hash_entry *e;
|
||||
struct hash_entry *end_e;
|
||||
|
||||
bool eq;
|
||||
|
||||
hash = 0;
|
||||
(*t->key->alg->hash) (&hash, t->key->size, data);
|
||||
hash &= ~HASH_MASK;
|
||||
hash += HASH_ADJUST (hash);
|
||||
for (;;) {
|
||||
int32 shift = HASH_BITS - (st->power + used);
|
||||
@ -319,7 +288,7 @@ hash_lookup (Hmap *h, void *data, void **pres)
|
||||
e = HASH_OFFSET (e, elemsize);
|
||||
}
|
||||
while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
|
||||
if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
|
||||
if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */
|
||||
*pres = e->data;
|
||||
return (1);
|
||||
}
|
||||
@ -331,16 +300,20 @@ hash_lookup (Hmap *h, void *data, void **pres)
|
||||
}
|
||||
|
||||
static int32
|
||||
hash_remove (Hmap *h, void *data, void *arg)
|
||||
hash_remove (MapType *t, Hmap *h, void *data)
|
||||
{
|
||||
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
|
||||
hash_hash_t hash;
|
||||
struct hash_subtable *st = h->st;
|
||||
int32 used = 0;
|
||||
hash_hash_t e_hash;
|
||||
struct hash_entry *e;
|
||||
struct hash_entry *end_e;
|
||||
bool eq;
|
||||
|
||||
hash = 0;
|
||||
(*t->key->alg->hash) (&hash, t->key->size, data);
|
||||
hash &= ~HASH_MASK;
|
||||
hash += HASH_ADJUST (hash);
|
||||
for (;;) {
|
||||
int32 shift = HASH_BITS - (st->power + used);
|
||||
@ -360,8 +333,9 @@ hash_remove (Hmap *h, void *data, void *arg)
|
||||
e = HASH_OFFSET (e, elemsize);
|
||||
}
|
||||
while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
|
||||
if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
|
||||
(*h->data_del) (h->datavo, arg, e->data);
|
||||
if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */
|
||||
if (h->indirectval)
|
||||
free (*(void**)((byte*)e->data + h->valoff));
|
||||
hash_remove_n (st, e, 1);
|
||||
h->count--;
|
||||
return (1);
|
||||
@ -373,10 +347,11 @@ hash_remove (Hmap *h, void *data, void *arg)
|
||||
}
|
||||
|
||||
static int32
|
||||
hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
Hmap *h, void *data, void **pres)
|
||||
{
|
||||
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
bool eq;
|
||||
|
||||
if ((flags & HASH_REHASH) == 0) {
|
||||
hash += HASH_ADJUST (hash);
|
||||
@ -409,7 +384,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
int32 ins_i = i;
|
||||
hash_hash_t ins_e_hash;
|
||||
while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) {
|
||||
if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */
|
||||
if (HASH_DATA_EQ (eq, t, h, data, ins_e->data)) { /* a match */
|
||||
*pres = ins_e->data;
|
||||
return (1);
|
||||
}
|
||||
@ -447,17 +422,22 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
|
||||
}
|
||||
h->changes++;
|
||||
if (st->power < h->max_power) {
|
||||
hash_grow (h, pst, flags);
|
||||
hash_grow (t, h, pst, flags);
|
||||
} else {
|
||||
hash_conv (h, st, flags, hash, start_e);
|
||||
hash_conv (t, h, st, flags, hash, start_e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32
|
||||
hash_insert (Hmap *h, void *data, void **pres)
|
||||
hash_insert (MapType *t, Hmap *h, void *data, void **pres)
|
||||
{
|
||||
int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres);
|
||||
uintptr hash;
|
||||
int32 rc;
|
||||
|
||||
hash = 0;
|
||||
(*t->key->alg->hash) (&hash, t->key->size, data);
|
||||
rc = hash_insert_internal (t, &h->st, 0, hash, h, data, pres);
|
||||
|
||||
h->count += (rc == 0); /* increment count if element didn't previously exist */
|
||||
return (rc);
|
||||
@ -528,7 +508,7 @@ Again:
|
||||
last = sub->last;
|
||||
|
||||
if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
|
||||
struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
|
||||
struct hash_entry *start = HASH_OFFSET (e, -(elemsize * HASH_MAX_PROBES));
|
||||
struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
|
||||
hash_hash_t last_hash = it->last_hash;
|
||||
if (start < sub->start) {
|
||||
@ -599,12 +579,13 @@ Again:
|
||||
}
|
||||
|
||||
static void
|
||||
hash_iter_init (Hmap *h, struct hash_iter *it)
|
||||
hash_iter_init (MapType *t, Hmap *h, struct hash_iter *it)
|
||||
{
|
||||
it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
|
||||
it->changes = h->changes;
|
||||
it->i = 0;
|
||||
it->h = h;
|
||||
it->t = t;
|
||||
it->last_hash = 0;
|
||||
it->subtable_state[0].e = h->st->entry;
|
||||
it->subtable_state[0].start = h->st->entry;
|
||||
@ -701,24 +682,6 @@ enum {
|
||||
MaxValsize = 256 - 64
|
||||
};
|
||||
|
||||
static void
|
||||
donothing(uint32 s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
USED(b);
|
||||
}
|
||||
|
||||
static void
|
||||
freedata(uint32 datavo, void *a, void *b)
|
||||
{
|
||||
void *p;
|
||||
|
||||
USED(a);
|
||||
p = *(void**)((byte*)b + datavo);
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void**
|
||||
hash_indirect(Hmap *h, void *p)
|
||||
{
|
||||
@ -734,8 +697,7 @@ Hmap*
|
||||
runtime·makemap_c(MapType *typ, int64 hint)
|
||||
{
|
||||
Hmap *h;
|
||||
int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
|
||||
void (*data_del)(uint32, void*, void*);
|
||||
int32 valsize_in_hash;
|
||||
Type *key, *val;
|
||||
|
||||
key = typ->key;
|
||||
@ -744,68 +706,30 @@ runtime·makemap_c(MapType *typ, int64 hint)
|
||||
if(hint < 0 || (int32)hint != hint)
|
||||
runtime·panicstring("makemap: size out of range");
|
||||
|
||||
keyalg = key->alg;
|
||||
valalg = val->alg;
|
||||
keysize = key->size;
|
||||
valsize = val->size;
|
||||
|
||||
if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) {
|
||||
runtime·printf("map(keyalg=%d)\n", keyalg);
|
||||
if(key->alg->hash == runtime·nohash)
|
||||
runtime·throw("runtime.makemap: unsupported map key type");
|
||||
}
|
||||
|
||||
if(valalg >= nelem(runtime·algarray)) {
|
||||
runtime·printf("map(valalg=%d)\n", valalg);
|
||||
runtime·throw("runtime.makemap: unsupported map value type");
|
||||
}
|
||||
|
||||
h = runtime·mal(sizeof(*h));
|
||||
|
||||
valsize_in_hash = valsize;
|
||||
data_del = donothing;
|
||||
if (valsize > MaxValsize) {
|
||||
valsize_in_hash = val->size;
|
||||
if (val->size > MaxValsize) {
|
||||
h->indirectval = 1;
|
||||
data_del = freedata;
|
||||
valsize_in_hash = sizeof(void*);
|
||||
}
|
||||
|
||||
// align value inside data so that mark-sweep gc can find it.
|
||||
// might remove in the future and just assume datavo == keysize.
|
||||
h->datavo = keysize;
|
||||
// Align value inside data so that mark-sweep gc can find it.
|
||||
h->valoff = key->size;
|
||||
if(valsize_in_hash >= sizeof(void*))
|
||||
h->datavo = runtime·rnd(keysize, sizeof(void*));
|
||||
h->valoff = runtime·rnd(key->size, sizeof(void*));
|
||||
|
||||
hash_init(h, h->datavo+valsize_in_hash,
|
||||
runtime·algarray[keyalg].hash,
|
||||
runtime·algarray[keyalg].equal,
|
||||
data_del,
|
||||
hint);
|
||||
|
||||
h->keysize = keysize;
|
||||
h->valsize = valsize;
|
||||
h->keyalg = &runtime·algarray[keyalg];
|
||||
h->valalg = &runtime·algarray[valalg];
|
||||
hash_init(h, h->valoff+valsize_in_hash, hint);
|
||||
|
||||
// these calculations are compiler dependent.
|
||||
// figure out offsets of map call arguments.
|
||||
|
||||
// func() (key, val)
|
||||
h->ko0 = runtime·rnd(sizeof(h), Structrnd);
|
||||
h->vo0 = runtime·rnd(h->ko0+keysize, val->align);
|
||||
|
||||
// func(key) (val[, pres])
|
||||
h->ko1 = runtime·rnd(sizeof(h), key->align);
|
||||
h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
|
||||
h->po1 = h->vo1 + valsize;
|
||||
|
||||
// func(key, val[, pres])
|
||||
h->ko2 = runtime·rnd(sizeof(h), key->align);
|
||||
h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
|
||||
h->po2 = h->vo2 + valsize;
|
||||
|
||||
if(debug) {
|
||||
runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
|
||||
h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2);
|
||||
runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
|
||||
h, key->size, val->size, key->alg, val->alg);
|
||||
}
|
||||
|
||||
return h;
|
||||
@ -834,9 +758,9 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
|
||||
byte *res;
|
||||
Type *elem;
|
||||
|
||||
elem = t->elem;
|
||||
if(h == nil) {
|
||||
elem = t->elem;
|
||||
runtime·algarray[elem->alg].copy(elem->size, av, nil);
|
||||
elem->alg->copy(elem->size, av, nil);
|
||||
*pres = false;
|
||||
return;
|
||||
}
|
||||
@ -845,12 +769,12 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
|
||||
runtime·gosched();
|
||||
|
||||
res = nil;
|
||||
if(hash_lookup(h, ak, (void**)&res)) {
|
||||
if(hash_lookup(t, h, ak, (void**)&res)) {
|
||||
*pres = true;
|
||||
h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
|
||||
elem->alg->copy(elem->size, av, hash_indirect(h, res+h->valoff));
|
||||
} else {
|
||||
*pres = false;
|
||||
h->valalg->copy(h->valsize, av, nil);
|
||||
elem->alg->copy(elem->size, av, nil);
|
||||
}
|
||||
}
|
||||
|
||||
@ -862,13 +786,8 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
|
||||
byte *ak, *av;
|
||||
bool pres;
|
||||
|
||||
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 + 1);
|
||||
av = ak + runtime·rnd(t->key->size, Structrnd);
|
||||
|
||||
runtime·mapaccess(t, h, ak, av, &pres);
|
||||
|
||||
@ -876,9 +795,9 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
|
||||
runtime·prints("runtime.mapaccess1: map=");
|
||||
runtime·printpointer(h);
|
||||
runtime·prints("; key=");
|
||||
h->keyalg->print(h->keysize, ak);
|
||||
t->key->alg->print(t->key->size, ak);
|
||||
runtime·prints("; val=");
|
||||
h->valalg->print(h->valsize, av);
|
||||
t->elem->alg->print(t->elem->size, av);
|
||||
runtime·prints("; pres=");
|
||||
runtime·printbool(pres);
|
||||
runtime·prints("\n");
|
||||
@ -892,15 +811,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
|
||||
{
|
||||
byte *ak, *av, *ap;
|
||||
|
||||
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 + 1);
|
||||
av = ak + runtime·rnd(t->key->size, Structrnd);
|
||||
ap = av + t->elem->size;
|
||||
|
||||
runtime·mapaccess(t, h, ak, av, ap);
|
||||
|
||||
@ -908,9 +821,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
|
||||
runtime·prints("runtime.mapaccess2: map=");
|
||||
runtime·printpointer(h);
|
||||
runtime·prints("; key=");
|
||||
h->keyalg->print(h->keysize, ak);
|
||||
t->key->alg->print(t->key->size, ak);
|
||||
runtime·prints("; val=");
|
||||
h->valalg->print(h->valsize, av);
|
||||
t->elem->alg->print(t->key->size, av);
|
||||
runtime·prints("; pres=");
|
||||
runtime·printbool(*ap);
|
||||
runtime·prints("\n");
|
||||
@ -949,33 +862,31 @@ 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");
|
||||
|
||||
if(runtime·gcwaiting)
|
||||
runtime·gosched();
|
||||
|
||||
res = nil;
|
||||
if(av == nil) {
|
||||
hash_remove(h, ak, (void**)&res);
|
||||
hash_remove(t, h, ak);
|
||||
return;
|
||||
}
|
||||
|
||||
hit = hash_insert(h, ak, (void**)&res);
|
||||
res = nil;
|
||||
hit = hash_insert(t, h, ak, (void**)&res);
|
||||
if(!hit && h->indirectval)
|
||||
*(void**)(res+h->datavo) = runtime·mal(h->valsize);
|
||||
h->keyalg->copy(h->keysize, res, ak);
|
||||
h->valalg->copy(h->valsize, hash_indirect(h, res+h->datavo), av);
|
||||
*(void**)(res+h->valoff) = runtime·mal(t->elem->size);
|
||||
t->key->alg->copy(t->key->size, res, ak);
|
||||
t->elem->alg->copy(t->elem->size, hash_indirect(h, res+h->valoff), av);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("mapassign: map=");
|
||||
runtime·printpointer(h);
|
||||
runtime·prints("; key=");
|
||||
h->keyalg->print(h->keysize, ak);
|
||||
t->key->alg->print(t->key->size, ak);
|
||||
runtime·prints("; val=");
|
||||
h->valalg->print(h->valsize, av);
|
||||
t->elem->alg->print(t->elem->size, av);
|
||||
runtime·prints("; hit=");
|
||||
runtime·printint(hit);
|
||||
runtime·prints("; res=");
|
||||
@ -994,8 +905,8 @@ runtime·mapassign1(MapType *t, Hmap *h, ...)
|
||||
if(h == nil)
|
||||
runtime·panicstring("assignment to entry in nil map");
|
||||
|
||||
ak = (byte*)&h + h->ko2;
|
||||
av = (byte*)&h + h->vo2;
|
||||
ak = (byte*)(&h + 1);
|
||||
av = ak + runtime·rnd(t->key->size, t->elem->align);
|
||||
|
||||
runtime·mapassign(t, h, ak, av);
|
||||
}
|
||||
@ -1010,14 +921,14 @@ runtime·mapdelete(MapType *t, Hmap *h, ...)
|
||||
if(h == nil)
|
||||
runtime·panicstring("deletion of entry in nil map");
|
||||
|
||||
ak = (byte*)&h + h->ko2;
|
||||
ak = (byte*)(&h + 1);
|
||||
runtime·mapassign(t, h, ak, nil);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("mapdelete: map=");
|
||||
runtime·printpointer(h);
|
||||
runtime·prints("; key=");
|
||||
h->keyalg->print(h->keysize, ak);
|
||||
t->key->alg->print(t->key->size, ak);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
}
|
||||
@ -1033,11 +944,11 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
|
||||
|
||||
if(h == nil)
|
||||
runtime·panicstring("assignment to entry in nil map");
|
||||
if(h->keysize <= sizeof(key))
|
||||
if(t->key->size <= sizeof(key))
|
||||
ak = (byte*)&key;
|
||||
else
|
||||
ak = (byte*)key;
|
||||
if(h->valsize <= sizeof(val))
|
||||
if(t->elem->size <= sizeof(val))
|
||||
av = (byte*)&val;
|
||||
else
|
||||
av = (byte*)val;
|
||||
@ -1048,13 +959,13 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
|
||||
|
||||
// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
|
||||
void
|
||||
runtime·mapiterinit(MapType*, Hmap *h, struct hash_iter *it)
|
||||
runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
|
||||
{
|
||||
if(h == nil) {
|
||||
it->data = nil;
|
||||
return;
|
||||
}
|
||||
hash_iter_init(h, it);
|
||||
hash_iter_init(t, h, it);
|
||||
it->data = hash_next(it);
|
||||
if(debug) {
|
||||
runtime·prints("runtime.mapiterinit: map=");
|
||||
@ -1109,15 +1020,17 @@ runtime·mapiter1(struct hash_iter *it, ...)
|
||||
{
|
||||
Hmap *h;
|
||||
byte *ak, *res;
|
||||
Type *key;
|
||||
|
||||
h = it->h;
|
||||
ak = (byte*)&it + h->ko0;
|
||||
ak = (byte*)(&it + 1);
|
||||
|
||||
res = it->data;
|
||||
if(res == nil)
|
||||
runtime·throw("runtime.mapiter1: key:val nil pointer");
|
||||
|
||||
h->keyalg->copy(h->keysize, ak, res);
|
||||
key = it->t->key;
|
||||
key->alg->copy(key->size, ak, res);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("mapiter2: iter=");
|
||||
@ -1131,14 +1044,14 @@ runtime·mapiter1(struct hash_iter *it, ...)
|
||||
bool
|
||||
runtime·mapiterkey(struct hash_iter *it, void *ak)
|
||||
{
|
||||
Hmap *h;
|
||||
byte *res;
|
||||
Type *key;
|
||||
|
||||
h = it->h;
|
||||
res = it->data;
|
||||
if(res == nil)
|
||||
return false;
|
||||
h->keyalg->copy(h->keysize, ak, res);
|
||||
key = it->t->key;
|
||||
key->alg->copy(key->size, ak, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1149,20 +1062,20 @@ runtime·mapiterkey(struct hash_iter *it, void *ak)
|
||||
void
|
||||
reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
|
||||
{
|
||||
Hmap *h;
|
||||
byte *res;
|
||||
Type *tkey;
|
||||
|
||||
key = 0;
|
||||
ok = false;
|
||||
h = it->h;
|
||||
res = it->data;
|
||||
if(res == nil) {
|
||||
key = 0;
|
||||
ok = false;
|
||||
} else {
|
||||
tkey = it->t->key;
|
||||
key = 0;
|
||||
if(h->keysize <= sizeof(key))
|
||||
h->keyalg->copy(h->keysize, (byte*)&key, res);
|
||||
if(tkey->size <= sizeof(key))
|
||||
tkey->alg->copy(tkey->size, (byte*)&key, res);
|
||||
else
|
||||
key = (uintptr)res;
|
||||
ok = true;
|
||||
@ -1191,17 +1104,19 @@ runtime·mapiter2(struct hash_iter *it, ...)
|
||||
{
|
||||
Hmap *h;
|
||||
byte *ak, *av, *res;
|
||||
MapType *t;
|
||||
|
||||
h = it->h;
|
||||
ak = (byte*)&it + h->ko0;
|
||||
av = (byte*)&it + h->vo0;
|
||||
t = it->t;
|
||||
ak = (byte*)(&it + 1);
|
||||
av = ak + runtime·rnd(t->key->size, t->elem->align);
|
||||
|
||||
res = it->data;
|
||||
if(res == nil)
|
||||
runtime·throw("runtime.mapiter2: key:val nil pointer");
|
||||
|
||||
h->keyalg->copy(h->keysize, ak, res);
|
||||
h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
|
||||
h = it->h;
|
||||
t->key->alg->copy(t->key->size, ak, res);
|
||||
t->elem->alg->copy(t->elem->size, av, hash_indirect(h, res+h->valoff));
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("mapiter2: iter=");
|
||||
|
@ -86,6 +86,7 @@ struct hash_iter {
|
||||
hash_hash_t last_hash; /* last hash value returned */
|
||||
hash_hash_t cycle; /* hash value where we started */
|
||||
struct Hmap *h; /* the hash table */
|
||||
MapType *t; /* the map type */
|
||||
struct hash_iter_sub {
|
||||
struct hash_entry *e; /* pointer into subtable */
|
||||
struct hash_entry *start; /* start of subtable */
|
||||
|
@ -159,17 +159,18 @@ out:
|
||||
static void
|
||||
copyin(Type *t, void *src, void **dst)
|
||||
{
|
||||
int32 wid, alg;
|
||||
uintptr size;
|
||||
void *p;
|
||||
Alg *alg;
|
||||
|
||||
wid = t->size;
|
||||
size = t->size;
|
||||
alg = t->alg;
|
||||
|
||||
if(wid <= sizeof(*dst))
|
||||
runtime·algarray[alg].copy(wid, dst, src);
|
||||
if(size <= sizeof(*dst))
|
||||
alg->copy(size, dst, src);
|
||||
else {
|
||||
p = runtime·mal(wid);
|
||||
runtime·algarray[alg].copy(wid, p, src);
|
||||
p = runtime·mal(size);
|
||||
alg->copy(size, p, src);
|
||||
*dst = p;
|
||||
}
|
||||
}
|
||||
@ -177,15 +178,16 @@ copyin(Type *t, void *src, void **dst)
|
||||
static void
|
||||
copyout(Type *t, void **src, void *dst)
|
||||
{
|
||||
int32 wid, alg;
|
||||
uintptr size;
|
||||
Alg *alg;
|
||||
|
||||
wid = t->size;
|
||||
size = t->size;
|
||||
alg = t->alg;
|
||||
|
||||
if(wid <= sizeof(*src))
|
||||
runtime·algarray[alg].copy(wid, dst, src);
|
||||
if(size <= sizeof(*src))
|
||||
alg->copy(size, dst, src);
|
||||
else
|
||||
runtime·algarray[alg].copy(wid, dst, *src);
|
||||
alg->copy(size, dst, *src);
|
||||
}
|
||||
|
||||
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
|
||||
@ -548,23 +550,27 @@ runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
|
||||
static uintptr
|
||||
ifacehash1(void *data, Type *t)
|
||||
{
|
||||
int32 alg, wid;
|
||||
Alg *alg;
|
||||
uintptr size, h;
|
||||
Eface err;
|
||||
|
||||
if(t == nil)
|
||||
return 0;
|
||||
|
||||
alg = t->alg;
|
||||
wid = t->size;
|
||||
if(runtime·algarray[alg].hash == runtime·nohash) {
|
||||
size = t->size;
|
||||
if(alg->hash == runtime·nohash) {
|
||||
// calling nohash will panic too,
|
||||
// but we can print a better error.
|
||||
runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
|
||||
runtime·panic(err);
|
||||
}
|
||||
if(wid <= sizeof(data))
|
||||
return runtime·algarray[alg].hash(wid, &data);
|
||||
return runtime·algarray[alg].hash(wid, data);
|
||||
h = 0;
|
||||
if(size <= sizeof(data))
|
||||
alg->hash(&h, size, &data);
|
||||
else
|
||||
alg->hash(&h, size, data);
|
||||
return h;
|
||||
}
|
||||
|
||||
uintptr
|
||||
@ -584,22 +590,27 @@ runtime·efacehash(Eface a)
|
||||
static bool
|
||||
ifaceeq1(void *data1, void *data2, Type *t)
|
||||
{
|
||||
int32 alg, wid;
|
||||
uintptr size;
|
||||
Alg *alg;
|
||||
Eface err;
|
||||
bool eq;
|
||||
|
||||
alg = t->alg;
|
||||
wid = t->size;
|
||||
size = t->size;
|
||||
|
||||
if(runtime·algarray[alg].equal == runtime·noequal) {
|
||||
if(alg->equal == runtime·noequal) {
|
||||
// calling noequal will panic too,
|
||||
// but we can print a better error.
|
||||
runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
|
||||
runtime·panic(err);
|
||||
}
|
||||
|
||||
if(wid <= sizeof(data1))
|
||||
return runtime·algarray[alg].equal(wid, &data1, &data2);
|
||||
return runtime·algarray[alg].equal(wid, data1, data2);
|
||||
eq = 0;
|
||||
if(size <= sizeof(data1))
|
||||
alg->equal(&eq, size, &data1, &data2);
|
||||
else
|
||||
alg->equal(&eq, size, data1, data2);
|
||||
return eq;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -701,7 +712,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
|
||||
if(e.type->size <= sizeof(uintptr)) {
|
||||
// Copy data into x ...
|
||||
x = 0;
|
||||
runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
|
||||
e.type->alg->copy(e.type->size, &x, &e.data);
|
||||
|
||||
// but then build pointer to x so that Reflect
|
||||
// always returns pointer to data.
|
||||
@ -711,7 +722,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
|
||||
// Already a pointer, but still make a copy,
|
||||
// to preserve value semantics for interface data.
|
||||
p = runtime·mal(e.type->size);
|
||||
runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
|
||||
e.type->alg->copy(e.type->size, p, e.data);
|
||||
}
|
||||
retaddr = p;
|
||||
}
|
||||
@ -734,7 +745,7 @@ unsafe·Unreflect(Eface typ, void *addr, Eface e)
|
||||
// Interface holds either pointer to data
|
||||
// or copy of original data.
|
||||
if(e.type->size <= sizeof(uintptr))
|
||||
runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
|
||||
e.type->alg->copy(e.type->size, &e.data, addr);
|
||||
else {
|
||||
// Easier: already a pointer to data.
|
||||
// TODO(rsc): Should this make a copy?
|
||||
|
@ -322,338 +322,6 @@ runtime·check(void)
|
||||
runtime·initsig(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* map and chan helpers for
|
||||
* dealing with unknown types
|
||||
*/
|
||||
static uintptr
|
||||
memhash(uint32 s, void *a)
|
||||
{
|
||||
byte *b;
|
||||
uintptr hash;
|
||||
|
||||
b = a;
|
||||
if(sizeof(hash) == 4)
|
||||
hash = 2860486313U;
|
||||
else
|
||||
hash = 33054211828000289ULL;
|
||||
while(s > 0) {
|
||||
if(sizeof(hash) == 4)
|
||||
hash = (hash ^ *b) * 3267000013UL;
|
||||
else
|
||||
hash = (hash ^ *b) * 23344194077549503ULL;
|
||||
b++;
|
||||
s--;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal(uint32 s, void *a, void *b)
|
||||
{
|
||||
byte *ba, *bb, *aend;
|
||||
|
||||
if(a == b)
|
||||
return 1;
|
||||
ba = a;
|
||||
bb = b;
|
||||
aend = ba+s;
|
||||
while(ba != aend) {
|
||||
if(*ba != *bb)
|
||||
return 0;
|
||||
ba++;
|
||||
bb++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
memprint(uint32 s, void *a)
|
||||
{
|
||||
uint64 v;
|
||||
|
||||
v = 0xbadb00b;
|
||||
switch(s) {
|
||||
case 1:
|
||||
v = *(uint8*)a;
|
||||
break;
|
||||
case 2:
|
||||
v = *(uint16*)a;
|
||||
break;
|
||||
case 4:
|
||||
v = *(uint32*)a;
|
||||
break;
|
||||
case 8:
|
||||
v = *(uint64*)a;
|
||||
break;
|
||||
}
|
||||
runtime·printint(v);
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy(uint32 s, void *a, void *b)
|
||||
{
|
||||
if(b == nil) {
|
||||
runtime·memclr(a,s);
|
||||
return;
|
||||
}
|
||||
runtime·memmove(a,b,s);
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal8(uint32 s, uint8 *a, uint8 *b)
|
||||
{
|
||||
USED(s);
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy8(uint32 s, uint8 *a, uint8 *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = 0;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal16(uint32 s, uint16 *a, uint16 *b)
|
||||
{
|
||||
USED(s);
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy16(uint32 s, uint16 *a, uint16 *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = 0;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal32(uint32 s, uint32 *a, uint32 *b)
|
||||
{
|
||||
USED(s);
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy32(uint32 s, uint32 *a, uint32 *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = 0;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal64(uint32 s, uint64 *a, uint64 *b)
|
||||
{
|
||||
USED(s);
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy64(uint32 s, uint64 *a, uint64 *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = 0;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
}
|
||||
|
||||
static uint32
|
||||
memequal128(uint32 s, uint64 *a, uint64 *b)
|
||||
{
|
||||
USED(s);
|
||||
return a[0] == b[0] && a[1] == b[1];
|
||||
}
|
||||
|
||||
static void
|
||||
memcopy128(uint32 s, uint64 *a, uint64 *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
a[0] = 0;
|
||||
a[1] = 0;
|
||||
return;
|
||||
}
|
||||
a[0] = b[0];
|
||||
a[1] = b[1];
|
||||
}
|
||||
|
||||
static void
|
||||
slicecopy(uint32 s, Slice *a, Slice *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
a->array = 0;
|
||||
a->len = 0;
|
||||
a->cap = 0;
|
||||
return;
|
||||
}
|
||||
a->array = b->array;
|
||||
a->len = b->len;
|
||||
a->cap = b->cap;
|
||||
}
|
||||
|
||||
static uintptr
|
||||
strhash(uint32 s, String *a)
|
||||
{
|
||||
USED(s);
|
||||
return memhash((*a).len, (*a).str);
|
||||
}
|
||||
|
||||
static uint32
|
||||
strequal(uint32 s, String *a, String *b)
|
||||
{
|
||||
int32 alen;
|
||||
|
||||
USED(s);
|
||||
alen = a->len;
|
||||
if(alen != b->len)
|
||||
return false;
|
||||
return memequal(alen, a->str, b->str);
|
||||
}
|
||||
|
||||
static void
|
||||
strprint(uint32 s, String *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printstring(*a);
|
||||
}
|
||||
|
||||
static void
|
||||
strcopy(uint32 s, String *a, String *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
a->str = 0;
|
||||
a->len = 0;
|
||||
return;
|
||||
}
|
||||
a->str = b->str;
|
||||
a->len = b->len;
|
||||
}
|
||||
|
||||
static uintptr
|
||||
interhash(uint32 s, Iface *a)
|
||||
{
|
||||
USED(s);
|
||||
return runtime·ifacehash(*a);
|
||||
}
|
||||
|
||||
static void
|
||||
interprint(uint32 s, Iface *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printiface(*a);
|
||||
}
|
||||
|
||||
static uint32
|
||||
interequal(uint32 s, Iface *a, Iface *b)
|
||||
{
|
||||
USED(s);
|
||||
return runtime·ifaceeq_c(*a, *b);
|
||||
}
|
||||
|
||||
static void
|
||||
intercopy(uint32 s, Iface *a, Iface *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
a->tab = 0;
|
||||
a->data = 0;
|
||||
return;
|
||||
}
|
||||
a->tab = b->tab;
|
||||
a->data = b->data;
|
||||
}
|
||||
|
||||
static uintptr
|
||||
nilinterhash(uint32 s, Eface *a)
|
||||
{
|
||||
USED(s);
|
||||
return runtime·efacehash(*a);
|
||||
}
|
||||
|
||||
static void
|
||||
nilinterprint(uint32 s, Eface *a)
|
||||
{
|
||||
USED(s);
|
||||
runtime·printeface(*a);
|
||||
}
|
||||
|
||||
static uint32
|
||||
nilinterequal(uint32 s, Eface *a, Eface *b)
|
||||
{
|
||||
USED(s);
|
||||
return runtime·efaceeq_c(*a, *b);
|
||||
}
|
||||
|
||||
static void
|
||||
nilintercopy(uint32 s, Eface *a, Eface *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
a->type = 0;
|
||||
a->data = 0;
|
||||
return;
|
||||
}
|
||||
a->type = b->type;
|
||||
a->data = b->data;
|
||||
}
|
||||
|
||||
uintptr
|
||||
runtime·nohash(uint32 s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
runtime·panicstring("hash of unhashable type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32
|
||||
runtime·noequal(uint32 s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
USED(b);
|
||||
runtime·panicstring("comparing uncomparable types");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Alg
|
||||
runtime·algarray[] =
|
||||
{
|
||||
[AMEM] { memhash, memequal, memprint, memcopy },
|
||||
[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy },
|
||||
[ASTRING] { (void*)strhash, (void*)strequal, (void*)strprint, (void*)strcopy },
|
||||
[AINTER] { (void*)interhash, (void*)interequal, (void*)interprint, (void*)intercopy },
|
||||
[ANILINTER] { (void*)nilinterhash, (void*)nilinterequal, (void*)nilinterprint, (void*)nilintercopy },
|
||||
[ASLICE] { (void*)runtime·nohash, (void*)runtime·noequal, (void*)memprint, (void*)slicecopy },
|
||||
[AMEM8] { memhash, (void*)memequal8, memprint, (void*)memcopy8 },
|
||||
[AMEM16] { memhash, (void*)memequal16, memprint, (void*)memcopy16 },
|
||||
[AMEM32] { memhash, (void*)memequal32, memprint, (void*)memcopy32 },
|
||||
[AMEM64] { memhash, (void*)memequal64, memprint, (void*)memcopy64 },
|
||||
[AMEM128] { memhash, (void*)memequal128, memprint, (void*)memcopy128 },
|
||||
[ANOEQ8] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy8 },
|
||||
[ANOEQ16] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy16 },
|
||||
[ANOEQ32] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy32 },
|
||||
[ANOEQ64] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy64 },
|
||||
[ANOEQ128] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy128 },
|
||||
};
|
||||
|
||||
void
|
||||
runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
|
||||
{
|
||||
|
@ -43,7 +43,6 @@ typedef int32 intptr;
|
||||
*/
|
||||
typedef uint8 bool;
|
||||
typedef uint8 byte;
|
||||
typedef struct Alg Alg;
|
||||
typedef struct Func Func;
|
||||
typedef struct G G;
|
||||
typedef struct Gobuf Gobuf;
|
||||
@ -260,13 +259,6 @@ struct Stktop
|
||||
uintptr free; // if free>0, call stackfree using free as size
|
||||
bool panic; // is this frame the top of a panic?
|
||||
};
|
||||
struct Alg
|
||||
{
|
||||
uintptr (*hash)(uint32, void*);
|
||||
uint32 (*equal)(uint32, void*, void*);
|
||||
void (*print)(uint32, void*);
|
||||
void (*copy)(uint32, void*, void*);
|
||||
};
|
||||
struct SigTab
|
||||
{
|
||||
int32 flags;
|
||||
@ -356,6 +348,13 @@ struct Timer
|
||||
/*
|
||||
* known to compiler
|
||||
*/
|
||||
enum {
|
||||
Structrnd = sizeof(uintptr)
|
||||
};
|
||||
|
||||
/*
|
||||
* type algorithms - known to compiler
|
||||
*/
|
||||
enum
|
||||
{
|
||||
AMEM,
|
||||
@ -376,12 +375,46 @@ enum
|
||||
ANOEQ128,
|
||||
Amax
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
Structrnd = sizeof(uintptr)
|
||||
typedef struct Alg Alg;
|
||||
struct Alg
|
||||
{
|
||||
void (*hash)(uintptr*, uintptr, void*);
|
||||
void (*equal)(bool*, uintptr, void*, void*);
|
||||
void (*print)(uintptr, void*);
|
||||
void (*copy)(uintptr, void*, void*);
|
||||
};
|
||||
|
||||
extern Alg runtime·algarray[Amax];
|
||||
|
||||
void runtime·memhash(uintptr*, uintptr, void*);
|
||||
void runtime·nohash(uintptr*, uintptr, void*);
|
||||
void runtime·strhash(uintptr*, uintptr, void*);
|
||||
void runtime·interhash(uintptr*, uintptr, void*);
|
||||
void runtime·nilinterhash(uintptr*, uintptr, void*);
|
||||
|
||||
void runtime·memequal(bool*, uintptr, void*, void*);
|
||||
void runtime·noequal(bool*, uintptr, void*, void*);
|
||||
void runtime·strequal(bool*, uintptr, void*, void*);
|
||||
void runtime·interequal(bool*, uintptr, void*, void*);
|
||||
void runtime·nilinterequal(bool*, uintptr, void*, void*);
|
||||
|
||||
void runtime·memprint(uintptr, void*);
|
||||
void runtime·strprint(uintptr, void*);
|
||||
void runtime·interprint(uintptr, void*);
|
||||
void runtime·nilinterprint(uintptr, void*);
|
||||
|
||||
void runtime·memcopy(uintptr, void*, void*);
|
||||
void runtime·memcopy8(uintptr, void*, void*);
|
||||
void runtime·memcopy16(uintptr, void*, void*);
|
||||
void runtime·memcopy32(uintptr, void*, void*);
|
||||
void runtime·memcopy64(uintptr, void*, void*);
|
||||
void runtime·memcopy128(uintptr, void*, void*);
|
||||
void runtime·memcopy(uintptr, void*, void*);
|
||||
void runtime·strcopy(uintptr, void*, void*);
|
||||
void runtime·algslicecopy(uintptr, void*, void*);
|
||||
void runtime·intercopy(uintptr, void*, void*);
|
||||
void runtime·nilintercopy(uintptr, void*, void*);
|
||||
|
||||
/*
|
||||
* deferred subroutine calls
|
||||
*/
|
||||
@ -410,7 +443,6 @@ struct Panic
|
||||
/*
|
||||
* external data
|
||||
*/
|
||||
extern Alg runtime·algarray[Amax];
|
||||
extern String runtime·emptystring;
|
||||
G* runtime·allg;
|
||||
G* runtime·lastg;
|
||||
@ -498,8 +530,6 @@ bool runtime·ifaceeq_c(Iface, Iface);
|
||||
bool runtime·efaceeq_c(Eface, Eface);
|
||||
uintptr runtime·ifacehash(Iface);
|
||||
uintptr runtime·efacehash(Eface);
|
||||
uintptr runtime·nohash(uint32, void*);
|
||||
uint32 runtime·noequal(uint32, void*, void*);
|
||||
void* runtime·malloc(uintptr size);
|
||||
void runtime·free(void *v);
|
||||
bool runtime·addfinalizer(void*, void(*fn)(void*), int32);
|
||||
|
@ -11,7 +11,7 @@ static int32 debug = 0;
|
||||
|
||||
static void makeslice1(SliceType*, int32, int32, Slice*);
|
||||
static void growslice1(SliceType*, Slice, int32, Slice *);
|
||||
void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
|
||||
void runtime·copy(Slice to, Slice fm, uintptr width, int32 ret);
|
||||
|
||||
// see also unsafe·NewArray
|
||||
// makeslice(typ *Type, len, cap int64) (ary []any);
|
||||
@ -290,9 +290,9 @@ runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, S
|
||||
}
|
||||
}
|
||||
|
||||
// slicecopy(to any, fr any, wid uint32) int
|
||||
// copy(to any, fr any, wid uint32) int
|
||||
void
|
||||
runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
|
||||
runtime·copy(Slice to, Slice fm, uintptr width, int32 ret)
|
||||
{
|
||||
if(fm.len == 0 || to.len == 0 || width == 0) {
|
||||
ret = 0;
|
||||
|
@ -27,15 +27,16 @@ type Type interface{}
|
||||
// All types begin with a few common fields needed for
|
||||
// the interface runtime.
|
||||
type commonType struct {
|
||||
size uintptr // size in bytes
|
||||
hash uint32 // hash of type; avoids computation in hash tables
|
||||
alg uint8 // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM)
|
||||
align uint8 // alignment of variable with this type
|
||||
fieldAlign uint8 // alignment of struct field with this type
|
||||
kind uint8 // enumeration for C
|
||||
string *string // string form; unnecessary but undeniably useful
|
||||
*uncommonType // (relatively) uncommon fields
|
||||
ptrToThis *Type // pointer to this type, if used in binary or has methods
|
||||
size uintptr // size in bytes
|
||||
hash uint32 // hash of type; avoids computation in hash tables
|
||||
_ uint8 // unused
|
||||
align uint8 // alignment of variable with this type
|
||||
fieldAlign uint8 // alignment of struct field with this type
|
||||
kind uint8 // enumeration for C
|
||||
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
|
||||
string *string // string form; unnecessary but undeniably useful
|
||||
*uncommonType // (relatively) uncommon fields
|
||||
ptrToThis *Type // pointer to this type, if used in binary or has methods
|
||||
}
|
||||
|
||||
// Values for commonType.kind.
|
||||
|
@ -23,10 +23,11 @@ struct CommonType
|
||||
{
|
||||
uintptr size;
|
||||
uint32 hash;
|
||||
uint8 alg;
|
||||
uint8 _unused;
|
||||
uint8 align;
|
||||
uint8 fieldAlign;
|
||||
uint8 kind;
|
||||
Alg *alg;
|
||||
String *string;
|
||||
UncommonType *x;
|
||||
Type *ptrto;
|
||||
|
Loading…
Reference in New Issue
Block a user