dalgsym(Type *t)
{
int ot;
- Sym *s, *hash, *eq;
+ Sym *s, *hash, *hashfunc, *eq;
char buf[100];
// dalgsym is only called for a type that needs an algorithm table,
eq = typesymprefix(".eq", t);
geneq(eq, t);
+ // make Go func (a closure) for calling the hash function from Go
+ hashfunc = typesymprefix(".hashfunc", t);
+ dsymptr(hashfunc, 0, hash, 0);
+ ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
+
// ../../pkg/runtime/runtime.h:/Alg
ot = 0;
- ot = dsymptr(s, ot, hash, 0);
+ ot = dsymptr(s, ot, hashfunc, 0);
ot = dsymptr(s, ot, eq, 0);
ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0);
switch(t->width) {
n = newname(sym);
n->class = PFUNC;
tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
typecheck(&tfn, Etype);
n->type = tfn->type;
return n;
n = newname(sym);
n->class = PFUNC;
tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
typecheck(&tfn, Etype);
n->type = tfn->type;
return n;
void
genhash(Sym *sym, Type *t)
{
- Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn;
+ Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r;
Node *hashel;
Type *first, *t1;
int old_safemode;
dclcontext = PEXTERN;
markdcl();
- // func sym(h *uintptr, s uintptr, p *T)
+ // func sym(p *T, s uintptr, h uintptr) uintptr
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
tfn = nod(OTFUNC, N, N);
fn->nname->ntype = tfn;
- n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR])));
+ n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
- nh = n->left;
+ np = n->left;
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
- n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+ n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
- np = n->left;
+ nh = n->left;
+ n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value
+ tfn->rlist = list(tfn->rlist, n);
funchdr(fn);
typecheck(&fn->nname->ntype, Etype);
colasdefn(n->list, n);
ni = n->list->n;
- // *h = *h<<3 | *h>>61
+ // TODO: with aeshash we don't need these shift/mul parts
+
+ // h = h<<3 | h>>61
n->nbody = list(n->nbody,
nod(OAS,
- nod(OIND, nh, N),
+ nh,
nod(OOR,
- nod(OLSH, nod(OIND, nh, N), nodintconst(3)),
- nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3)))));
+ nod(OLSH, nh, nodintconst(3)),
+ nod(ORSH, nh, nodintconst(widthptr*8-3)))));
- // *h *= mul
+ // h *= mul
// Same multipliers as in runtime.memhash.
if(widthptr == 4)
mul = 3267000013LL;
mul = 23344194077549503LL;
n->nbody = list(n->nbody,
nod(OAS,
- nod(OIND, nh, N),
- nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));
+ nh,
+ nod(OMUL, nh, nodintconst(mul))));
- // hashel(h, sizeof(p[i]), &p[i])
+ // h = hashel(&p[i], sizeof(p[i]), h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(t->type->width));
nx = nod(OINDEX, np, ni);
nx->bounded = 1;
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- n->nbody = list(n->nbody, call);
+ call->list = list(call->list, nodintconst(t->type->width));
+ call->list = list(call->list, nh);
+ n->nbody = list(n->nbody, nod(OAS, nh, call));
fn->nbody = list(fn->nbody, n);
break;
if(first != T) {
size = offend - first->width; // first->width is offset
hashel = hashmem(first->type);
- // hashel(h, size, &p.first)
+ // h = hashel(&p.first, size, h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(size));
nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- fn->nbody = list(fn->nbody, call);
+ call->list = list(call->list, nodintconst(size));
+ call->list = list(call->list, nh);
+ fn->nbody = list(fn->nbody, nod(OAS, nh, call));
first = T;
}
// Run hash for this field.
hashel = hashfor(t1->type);
- // hashel(h, size, &p.t1)
+ // h = hashel(&p.t1, size, h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(t1->type->width));
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- fn->nbody = list(fn->nbody, call);
+ call->list = list(call->list, nodintconst(t1->type->width));
+ call->list = list(call->list, nh);
+ fn->nbody = list(fn->nbody, nod(OAS, nh, call));
}
- // make sure body is not empty.
- fn->nbody = list(fn->nbody, nod(ORETURN, N, N));
break;
}
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nh);
+ fn->nbody = list(fn->nbody, r);
if(debug['r'])
dumplist("genhash body", fn->nbody);
#include "type.h"
#include "../../cmd/ld/textflag.h"
-#define M0 (sizeof(uintptr)==4 ? 2860486313UL : 33054211828000289ULL)
-#define M1 (sizeof(uintptr)==4 ? 3267000013UL : 23344194077549503ULL)
-
-static bool use_aeshash;
-
-/*
- * map and chan helpers for
- * dealing with unknown types
- */
-void
-runtime·memhash(uintptr *h, uintptr s, void *a)
-{
- byte *b;
- uintptr hash;
- if(!NaCl && use_aeshash) {
- runtime·aeshash(h, s, a);
- return;
- }
-
- b = a;
- hash = M0 ^ *h;
- while(s > 0) {
- hash = (hash ^ *b) * M1;
- b++;
- s--;
- }
- *h = hash;
-}
+bool runtime·use_aeshash;
void
runtime·memequal(bool *eq, uintptr s, void *a, void *b)
*eq = ca->real == cb->real && ca->imag == cb->imag;
}
-// NOTE: Because NaN != NaN, a map can contain any
-// number of (mostly useless) entries keyed with NaNs.
-// To avoid long hash chains, we assign a random number
-// as the hash value for a NaN.
-
-void
-runtime·f32hash(uintptr *h, uintptr s, void *a)
-{
- uintptr hash;
- float32 f;
-
- USED(s);
- f = *(float32*)a;
- if(f == 0)
- hash = 0; // +0, -0
- else if(f != f)
- hash = runtime·fastrand1(); // any kind of NaN
- else
- hash = *(uint32*)a;
- *h = (*h ^ hash ^ M0) * M1;
-}
-
-void
-runtime·f64hash(uintptr *h, uintptr s, void *a)
-{
- uintptr hash;
- float64 f;
- uint64 u;
-
- USED(s);
- f = *(float64*)a;
- if(f == 0)
- hash = 0; // +0, -0
- else if(f != f)
- hash = runtime·fastrand1(); // any kind of NaN
- else {
- u = *(uint64*)a;
- if(sizeof(uintptr) == 4)
- hash = ((uint32)(u>>32) * M1) ^ (uint32)u;
- else
- hash = u;
- }
- *h = (*h ^ hash ^ M0) * M1;
-}
-
-void
-runtime·c64hash(uintptr *h, uintptr s, void *a)
-{
- USED(s);
- runtime·f32hash(h, 0, a);
- runtime·f32hash(h, 0, (float32*)a+1);
-}
-
-void
-runtime·c128hash(uintptr *h, uintptr s, void *a)
-{
- USED(s);
- runtime·f64hash(h, 0, a);
- runtime·f64hash(h, 0, (float64*)a+1);
-}
-
void
runtime·algslicecopy(uintptr s, void *a, void *b)
{
((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)
{
((String*)a)->len = ((String*)b)->len;
}
-void
-runtime·interhash(uintptr *h, uintptr s, void *a)
-{
- USED(s);
- *h = runtime·ifacehash(*(Iface*)a, *h ^ M0) * M1;
-}
-
void
runtime·interprint(uintptr s, void *a)
{
((Iface*)a)->data = ((Iface*)b)->data;
}
-void
-runtime·nilinterhash(uintptr *h, uintptr s, void *a)
-{
- USED(s);
- *h = runtime·efacehash(*(Eface*)a, *h ^ M0) * M1;
-}
-
void
runtime·nilinterprint(uintptr s, void *a)
{
((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");
-}
-
extern uintptr runtime·nohashcode;
void
runtime·panicstring("comparing uncomparable types");
}
+static FuncVal memhashfunc = {(void*)runtime·memhash};
+static FuncVal nohashfunc = {(void*)runtime·nohash};
+static FuncVal strhashfunc = {(void*)runtime·strhash};
+static FuncVal interhashfunc = {(void*)runtime·interhash};
+static FuncVal nilinterhashfunc = {(void*)runtime·nilinterhash};
+static FuncVal f32hashfunc = {(void*)runtime·f32hash};
+static FuncVal f64hashfunc = {(void*)runtime·f64hash};
+static FuncVal c64hashfunc = {(void*)runtime·c64hash};
+static FuncVal c128hashfunc = {(void*)runtime·c128hash};
+
+static FuncVal aeshashfunc = {(void*)runtime·aeshash};
+static FuncVal aeshash32func = {(void*)runtime·aeshash32};
+static FuncVal aeshash64func = {(void*)runtime·aeshash64};
+static FuncVal aeshashstrfunc = {(void*)runtime·aeshashstr};
+
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·algslicecopy },
-[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
-[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
-[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
-[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
-[AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
-[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 },
-[ANOEQ0] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy0 },
-[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 },
+[AMEM] { &memhashfunc, runtime·memequal, runtime·memprint, runtime·memcopy },
+[ANOEQ] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy },
+[ASTRING] { &strhashfunc, runtime·strequal, runtime·strprint, runtime·strcopy },
+[AINTER] { &interhashfunc, runtime·interequal, runtime·interprint, runtime·intercopy },
+[ANILINTER] { &nilinterhashfunc, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
+[ASLICE] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·algslicecopy },
+[AFLOAT32] { &f32hashfunc, runtime·f32equal, runtime·memprint, runtime·memcopy },
+[AFLOAT64] { &f64hashfunc, runtime·f64equal, runtime·memprint, runtime·memcopy },
+[ACPLX64] { &c64hashfunc, runtime·c64equal, runtime·memprint, runtime·memcopy },
+[ACPLX128] { &c128hashfunc, runtime·c128equal, runtime·memprint, runtime·memcopy },
+[AMEM0] { &memhashfunc, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
+[AMEM8] { &memhashfunc, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
+[AMEM16] { &memhashfunc, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
+[AMEM32] { &memhashfunc, runtime·memequal32, runtime·memprint, runtime·memcopy32 },
+[AMEM64] { &memhashfunc, runtime·memequal64, runtime·memprint, runtime·memcopy64 },
+[AMEM128] { &memhashfunc, runtime·memequal128, runtime·memprint, runtime·memcopy128 },
+[ANOEQ0] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy0 },
+[ANOEQ8] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy8 },
+[ANOEQ16] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy16 },
+[ANOEQ32] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy32 },
+[ANOEQ64] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy64 },
+[ANOEQ128] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy128 },
};
// Runtime helpers.
(runtime·cpuid_ecx & (1 << 19)) != 0) { // sse4.1 (pinsr{d,q})
byte *rnd;
int32 n;
- use_aeshash = true;
- runtime·algarray[AMEM].hash = runtime·aeshash;
- runtime·algarray[AMEM8].hash = runtime·aeshash;
- runtime·algarray[AMEM16].hash = runtime·aeshash;
- runtime·algarray[AMEM32].hash = runtime·aeshash32;
- runtime·algarray[AMEM64].hash = runtime·aeshash64;
- runtime·algarray[AMEM128].hash = runtime·aeshash;
- runtime·algarray[ASTRING].hash = runtime·aeshashstr;
-
+ runtime·use_aeshash = true;
+ runtime·algarray[AMEM].hash = &aeshashfunc;
+ runtime·algarray[AMEM8].hash = &aeshashfunc;
+ runtime·algarray[AMEM16].hash = &aeshashfunc;
+ runtime·algarray[AMEM32].hash = &aeshash32func;
+ runtime·algarray[AMEM64].hash = &aeshash64func;
+ runtime·algarray[AMEM128].hash = &aeshashfunc;
+ runtime·algarray[ASTRING].hash = &aeshashstrfunc;
// Initialize with random data so hash collisions will be hard to engineer.
runtime·get_random_data(&rnd, &n);
if(n > HashRandomBytes)
func memclrBytes(s Slice) {
runtime·memclr(s.array, s.len);
}
-
-// Testing adapters for hash quality tests (see hash_test.go)
-func haveGoodHash() (res bool) {
- res = use_aeshash;
-}
-
-func stringHash(s String, seed uintptr) (res uintptr) {
- runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
- res = seed;
-}
-
-func bytesHash(s Slice, seed uintptr) (res uintptr) {
- runtime·algarray[AMEM].hash(&seed, s.len, s.array);
- res = seed;
-}
-
-func int32Hash(i uint32, seed uintptr) (res uintptr) {
- runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
- res = seed;
-}
-
-func int64Hash(i uint64, seed uintptr) (res uintptr) {
- runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
- res = seed;
-}
GLOBL runtime·tls0(SB), $32
// hash function using AES hardware instructions
-TEXT runtime·aeshash(SB),NOSPLIT,$0-12
- MOVL 4(SP), DX // ptr to hash value
- MOVL 8(SP), CX // size
- MOVL 12(SP), AX // ptr to data
+TEXT runtime·aeshash(SB),NOSPLIT,$0-16
+ MOVL p+0(FP), AX // ptr to data
+ MOVL s+4(FP), CX // size
JMP runtime·aeshashbody(SB)
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
- MOVL 4(SP), DX // ptr to hash value
- MOVL 12(SP), AX // ptr to string struct
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-16
+ MOVL p+0(FP), AX // ptr to string object
+ // s+4(FP) is ignored, it is always sizeof(String)
MOVL 4(AX), CX // length of string
MOVL (AX), AX // string data
JMP runtime·aeshashbody(SB)
// AX: data
// CX: length
-// DX: ptr to seed input / hash output
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-12
- MOVL (DX), X0 // seed to low 32 bits of xmm0
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-16
+ MOVL h+8(FP), X0 // seed to low 32 bits of xmm0
PINSRD $1, CX, X0 // size to next 32 bits of xmm0
MOVO runtime·aeskeysched+0(SB), X2
MOVO runtime·aeskeysched+16(SB), X3
AESENC X2, X0
AESENC X3, X0
AESENC X2, X0
- MOVL X0, (DX)
+ MOVL X0, res+12(FP)
RET
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
- MOVL 4(SP), DX // ptr to hash value
- MOVL 12(SP), AX // ptr to data
- MOVL (DX), X0 // seed
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-16
+ MOVL p+0(FP), AX // ptr to data
+ // s+4(FP) is ignored, it is always sizeof(int32)
+ MOVL h+8(FP), X0 // seed
PINSRD $1, (AX), X0 // data
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+0(SB), X0
- MOVL X0, (DX)
+ MOVL X0, res+12(FP)
RET
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
- MOVL 4(SP), DX // ptr to hash value
- MOVL 12(SP), AX // ptr to data
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-16
+ MOVL p+0(FP), AX // ptr to data
+ // s+4(FP) is ignored, it is always sizeof(int64)
MOVQ (AX), X0 // data
- PINSRD $2, (DX), X0 // seed
+ PINSRD $2, h+8(FP), X0 // seed
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+0(SB), X0
- MOVL X0, (DX)
+ MOVL X0, res+12(FP)
RET
// simple mask to get rid of data in the high part of the register.
MOVL DX, ret+0(FP)
RET
-// The gohash and goeq trampolines are necessary while we have
+// The goeq trampoline is necessary while we have
// both Go and C calls to alg functions. Once we move all call
-// sites to Go, we can redo the hash/eq functions to use the
-// Go calling convention and remove these.
-
-// convert call to:
-// func (alg unsafe.Pointer, p unsafe.Pointer, size uintpr, seed uintptr) uintptr
-// to:
-// func (hash *uintptr, size uintptr, p unsafe.Pointer)
-TEXT runtime·gohash(SB), NOSPLIT, $12-20
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_gohash<>(SB)
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_gohash<>(SB)
- MOVL a+0(FP), AX
- MOVL alg_hash(AX), AX
- MOVL p+4(FP), CX
- MOVL size+8(FP), DX
- MOVL seed+12(FP), DI
- MOVL DI, ret+16(FP)
- LEAL ret+16(FP), SI
- MOVL SI, 0(SP)
- MOVL DX, 4(SP)
- MOVL CX, 8(SP)
- PCDATA $PCDATA_StackMapIndex, $0
- CALL *AX
- RET
-
-DATA gcargs_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_gohash<>+0x04(SB)/4, $10 // 5 args
-DATA gcargs_gohash<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2))
-GLOBL gcargs_gohash<>(SB),RODATA,$12
-
-DATA gclocals_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_gohash<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_gohash<>(SB),RODATA,$8
+// sites to Go, we can redo the eq functions to use the
+// Go calling convention and remove this.
// convert call to:
// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool
GLOBL runtime·tls0(SB), $64
// hash function using AES hardware instructions
-TEXT runtime·aeshash(SB),NOSPLIT,$0-24
- MOVQ 8(SP), DX // ptr to hash value
- MOVQ 16(SP), CX // size
- MOVQ 24(SP), AX // ptr to data
+TEXT runtime·aeshash(SB),NOSPLIT,$0-32
+ MOVQ p+0(FP), AX // ptr to data
+ MOVQ s+8(FP), CX // size
JMP runtime·aeshashbody(SB)
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
- MOVQ 8(SP), DX // ptr to hash value
- MOVQ 24(SP), AX // ptr to string struct
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-32
+ MOVQ p+0(FP), AX // ptr to string struct
+ // s+8(FP) is ignored, it is always sizeof(String)
MOVQ 8(AX), CX // length of string
MOVQ (AX), AX // string data
JMP runtime·aeshashbody(SB)
// AX: data
// CX: length
-// DX: ptr to seed input / hash output
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-24
- MOVQ (DX), X0 // seed to low 64 bits of xmm0
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-32
+ MOVQ h+16(FP), X0 // seed to low 64 bits of xmm0
PINSRQ $1, CX, X0 // size to high 64 bits of xmm0
MOVO runtime·aeskeysched+0(SB), X2
MOVO runtime·aeskeysched+16(SB), X3
AESENC X2, X0
AESENC X3, X0
AESENC X2, X0
- MOVQ X0, (DX)
+ MOVQ X0, res+24(FP)
RET
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
- MOVQ 8(SP), DX // ptr to hash value
- MOVQ 24(SP), AX // ptr to data
- MOVQ (DX), X0 // seed
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-32
+ MOVQ p+0(FP), AX // ptr to data
+ // s+8(FP) is ignored, it is always sizeof(int32)
+ MOVQ h+16(FP), X0 // seed
PINSRD $2, (AX), X0 // data
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+0(SB), X0
- MOVQ X0, (DX)
+ MOVQ X0, res+24(FP)
RET
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
- MOVQ 8(SP), DX // ptr to hash value
- MOVQ 24(SP), AX // ptr to data
- MOVQ (DX), X0 // seed
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-32
+ MOVQ p+0(FP), AX // ptr to data
+ // s+8(FP) is ignored, it is always sizeof(int64)
+ MOVQ h+16(FP), X0 // seed
PINSRQ $1, (AX), X0 // data
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+0(SB), X0
- MOVQ X0, (DX)
+ MOVQ X0, res+24(FP)
RET
// simple mask to get rid of data in the high part of the register.
MOVL DX, ret+0(FP)
RET
-// The gohash and goeq trampolines are necessary while we have
+// goeq trampoline is necessary while we have
// both Go and C calls to alg functions. Once we move all call
-// sites to Go, we can redo the hash/eq functions to use the
-// Go calling convention and remove these.
-
-// convert call to:
-// func (alg unsafe.Pointer, p unsafe.Pointer, size uintpr, seed uintptr) uintptr
-// to:
-// func (hash *uintptr, size uintptr, p unsafe.Pointer)
-TEXT runtime·gohash(SB), NOSPLIT, $24-40
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_gohash<>(SB)
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_gohash<>(SB)
- MOVQ a+0(FP), AX
- MOVQ alg_hash(AX), AX
- MOVQ p+8(FP), CX
- MOVQ size+16(FP), DX
- MOVQ seed+24(FP), DI
- MOVQ DI, ret+32(FP)
- LEAQ ret+32(FP), SI
- MOVQ SI, 0(SP)
- MOVQ DX, 8(SP)
- MOVQ CX, 16(SP)
- PCDATA $PCDATA_StackMapIndex, $0
- CALL *AX
- RET
-
-DATA gcargs_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_gohash<>+0x04(SB)/4, $10 // 5 args
-DATA gcargs_gohash<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2))
-GLOBL gcargs_gohash<>(SB),RODATA,$12
-
-DATA gclocals_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_gohash<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_gohash<>(SB),RODATA,$8
+// sites to Go, we can redo the eq function to use the
+// Go calling convention and remove this.
// convert call to:
// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool
MOVL DX, ret+0(FP)
RET
-// The gohash and goeq trampolines are necessary while we have
+// The goeq trampoline is necessary while we have
// both Go and C calls to alg functions. Once we move all call
-// sites to Go, we can redo the hash/eq functions to use the
-// Go calling convention and remove these.
-
-// convert call to:
-// func (alg unsafe.Pointer, p unsafe.Pointer, size uintpr, seed uintptr) uintptr
-// to:
-// func (hash *uintptr, size uintptr, p unsafe.Pointer)
-TEXT runtime·gohash(SB), NOSPLIT, $16-20
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_gohash<>(SB)
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_gohash<>(SB)
- MOVL a+0(FP), AX
- MOVL alg_hash(AX), AX
- MOVL p+4(FP), CX
- MOVL size+8(FP), DX
- MOVL seed+12(FP), DI
- MOVL DI, ret+16(FP)
- LEAL ret+16(FP), SI
- MOVL SI, 0(SP)
- MOVL DX, 4(SP)
- MOVL CX, 8(SP)
- PCDATA $PCDATA_StackMapIndex, $0
- CALL *AX
- RET
-
-DATA gcargs_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_gohash<>+0x04(SB)/4, $10 // 5 args
-DATA gcargs_gohash<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2))
-GLOBL gcargs_gohash<>(SB),RODATA,$12
-
-DATA gclocals_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_gohash<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_gohash<>(SB),RODATA,$8
+// sites to Go, we can redo the eq functions to use the
+// Go calling convention and remove this.
// convert call to:
// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool
MOVW R0, ret+0(FP)
RET
-// The gohash and goeq trampolines are necessary while we have
+// The goeq trampoline is necessary while we have
// both Go and C calls to alg functions. Once we move all call
-// sites to Go, we can redo the hash/eq functions to use the
-// Go calling convention and remove these.
-
-// convert call to:
-// func (alg unsafe.Pointer, p unsafe.Pointer, size uintpr, seed uintptr) uintptr
-// to:
-// func (hash *uintptr, size uintptr, p unsafe.Pointer)
-TEXT runtime·gohash(SB), NOSPLIT, $12-20
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_gohash<>(SB)
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_gohash<>(SB)
- MOVW a+0(FP), R0
- MOVW alg_hash(R0), R0
- MOVW p+4(FP), R1
- MOVW size+8(FP), R2
- MOVW seed+12(FP), R3
- MOVW R3, ret+16(FP)
- ADD $36, R13, R4
- MOVW R4, 4(R13)
- MOVW R2, 8(R13)
- MOVW R1, 12(R13)
- PCDATA $PCDATA_StackMapIndex, $0
- BL (R0)
- RET
-
-DATA gcargs_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_gohash<>+0x04(SB)/4, $10 // 5 args
-DATA gcargs_gohash<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2))
-GLOBL gcargs_gohash<>(SB),RODATA,$12
-
-DATA gclocals_gohash<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_gohash<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_gohash<>(SB),RODATA,$8
+// sites to Go, we can redo the eq functions to use the
+// Go calling convention and remove this.
// convert call to:
// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool
var TestSchedLocalQueue1 = testSchedLocalQueue
var TestSchedLocalQueueSteal1 = testSchedLocalQueueSteal
-func haveGoodHash() bool
-func stringHash(s string, seed uintptr) uintptr
-func bytesHash(b []byte, seed uintptr) uintptr
-func int32Hash(i uint32, seed uintptr) uintptr
-func int64Hash(i uint64, seed uintptr) uintptr
-
var HaveGoodHash = haveGoodHash
var StringHash = stringHash
var BytesHash = bytesHash
if h == nil || h.count == 0 {
return unsafe.Pointer(t.elem.zero)
}
- hash := gohash(t.key.alg, key, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
if h == nil || h.count == 0 {
return unsafe.Pointer(t.elem.zero), false
}
- hash := gohash(t.key.alg, key, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
if h == nil || h.count == 0 {
return nil, nil
}
- hash := gohash(t.key.alg, key, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
raceReadObjectPC(t.elem, val, callerpc, pc)
}
- hash := gohash(t.key.alg, key, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
if h.buckets == nil {
if checkgc {
if h == nil || h.count == 0 {
return
}
- hash := gohash(t.key.alg, key, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
bucket := hash & (uintptr(1)<<h.B - 1)
if h.oldbuckets != nil {
growWork(t, h, bucket)
if goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
// If the item in the oldbucket is not destined for
// the current new bucket in the iteration, skip it.
- hash := gohash(t.key.alg, k2, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(k2, uintptr(t.key.size), uintptr(h.hash0))
if hash&(uintptr(1)<<it.B-1) != checkBucket {
continue
}
}
// Compute hash to make our evacuation decision (whether we need
// to send this key/value to bucket x or bucket y).
- hash := gohash(t.key.alg, k2, uintptr(t.key.size), uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(k2, uintptr(t.key.size), uintptr(h.hash0))
if h.flags&iterator != 0 {
if !goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
// If key != key (NaNs), then the hash could be (and probably
}
func ismapkey(t *_type) bool {
- return *(*uintptr)(unsafe.Pointer(&t.alg.hash)) != nohashcode
+ return **(**uintptr)(unsafe.Pointer(&t.alg.hash)) != nohashcode
}
// Reflect stubs. Called from ../reflect/asm_*.s
// One-bucket table. No need to hash.
b = (*bmap)(h.buckets)
} else {
- hash := gohash(t.key.alg, unsafe.Pointer(&key), 4, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
// One-bucket table. No need to hash.
b = (*bmap)(h.buckets)
} else {
- hash := gohash(t.key.alg, unsafe.Pointer(&key), 4, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
// One-bucket table. No need to hash.
b = (*bmap)(h.buckets)
} else {
- hash := gohash(t.key.alg, unsafe.Pointer(&key), 8, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
// One-bucket table. No need to hash.
b = (*bmap)(h.buckets)
} else {
- hash := gohash(t.key.alg, unsafe.Pointer(&key), 8, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
return unsafe.Pointer(t.elem.zero)
}
dohash:
- hash := gohash(t.key.alg, unsafe.Pointer(&ky), 2*ptrSize, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
return unsafe.Pointer(t.elem.zero), false
}
dohash:
- hash := gohash(t.key.alg, unsafe.Pointer(&ky), 2*ptrSize, uintptr(h.hash0))
+ hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
if c := h.oldbuckets; c != nil {
alg = t->alg;
size = t->size;
- if(alg->hash == runtime·nohash) {
+ if(alg->hash->fn == (void(*)())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(size <= sizeof(data))
- alg->hash(&h, size, &data);
+ return ((uintptr(*)(void**,uintptr,uintptr))alg->hash)(&data, size, h);
else
- alg->hash(&h, size, data);
- return h;
+ return ((uintptr(*)(void*,uintptr,uintptr))alg->hash)(data, size, h);
}
uintptr
typedef struct Alg Alg;
struct Alg
{
- void (*hash)(uintptr*, uintptr, void*);
+ FuncVal* hash;
void (*equal)(bool*, uintptr, void*, void*);
void (*print)(uintptr, void*);
void (*copy)(uintptr, void*, void*);
};
void runtime·hashinit(void);
-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·aeshash(uintptr*, uintptr, void*);
-void runtime·aeshash32(uintptr*, uintptr, void*);
-void runtime·aeshash64(uintptr*, uintptr, void*);
-void runtime·aeshashstr(uintptr*, uintptr, void*);
+uintptr runtime·memhash(void*, uintptr, uintptr);
+uintptr runtime·nohash(void*, uintptr, uintptr);
+uintptr runtime·strhash(void*, uintptr, uintptr);
+uintptr runtime·interhash(void*, uintptr, uintptr);
+uintptr runtime·nilinterhash(void*, uintptr, uintptr);
+uintptr runtime·f32hash(void*, uintptr, uintptr);
+uintptr runtime·f64hash(void*, uintptr, uintptr);
+uintptr runtime·c64hash(void*, uintptr, uintptr);
+uintptr runtime·c128hash(void*, uintptr, uintptr);
+uintptr runtime·aeshash(void*, uintptr, uintptr);
+uintptr runtime·aeshash32(void*, uintptr, uintptr);
+uintptr runtime·aeshash64(void*, uintptr, uintptr);
+uintptr runtime·aeshashstr(void*, uintptr, uintptr);
void runtime·memequal(bool*, uintptr, void*, void*);
void runtime·noequal(bool*, uintptr, void*, void*);
func gounlock(x *lock)
func semacquire(*uint32, bool)
func semrelease(*uint32)
+
+// Return the Go equivalent of the C Alg structure.
+// TODO: at some point Go will hold the truth for the layout
+// of runtime structures and C will be derived from it (if
+// needed at all). At that point this function can go away.
+type goalgtype struct {
+ // function for hashing objects of this type
+ // (ptr to object, size, seed) -> hash
+ hash func(unsafe.Pointer, uintptr, uintptr) uintptr
+}
+
+func goalg(a *alg) *goalgtype {
+ return (*goalgtype)(unsafe.Pointer(a))
+}
+
+// noescape hides a pointer from escape analysis. noescape is
+// the identity function but escape analysis doesn't think the
+// output depends on the input. noescape is inlined and currently
+// compiles down to a single xor instruction.
+// USE CAREFULLY!
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+ x := uintptr(p)
+ return unsafe.Pointer(x ^ 0)
+}