1
0
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:
Russ Cox 2011-12-05 09:40:22 -05:00
parent 263c955f2f
commit b9ccd077dc
19 changed files with 670 additions and 722 deletions

View File

@ -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";

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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*

View File

@ -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

View File

@ -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
View 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 },
};

View File

@ -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;

View File

@ -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=");

View File

@ -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 */

View File

@ -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?

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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;