aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-07-31 15:07:05 -0700
committerKeith Randall <khr@golang.org>2014-07-31 15:07:05 -0700
commita2a97684146d63cbde77b5c95b4403da53b79459 (patch)
treea1cd100c7579213520ac8db4beb48c5868537cf3 /src/pkg/runtime
parent5a3336096f19c7c813305f548e054b86391874ff (diff)
downloadgo-a2a97684146d63cbde77b5c95b4403da53b79459.tar.xz
runtime: convert hash functions to Go calling convention.
Create proper closures so hash functions can be called directly from Go. Rearrange calling convention so return value is directly accessible. LGTM=dvyukov R=golang-codereviews, dvyukov, dave, khr CC=golang-codereviews https://golang.org/cl/119360043
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/alg.goc221
-rw-r--r--src/pkg/runtime/asm_386.s76
-rw-r--r--src/pkg/runtime/asm_amd64.s76
-rw-r--r--src/pkg/runtime/asm_amd64p32.s36
-rw-r--r--src/pkg/runtime/asm_arm.s36
-rw-r--r--src/pkg/runtime/export_test.go6
-rw-r--r--src/pkg/runtime/hashmap.go16
-rw-r--r--src/pkg/runtime/hashmap_fast.go12
-rw-r--r--src/pkg/runtime/iface.goc7
-rw-r--r--src/pkg/runtime/runtime.h24
-rw-r--r--src/pkg/runtime/stubs.go24
11 files changed, 151 insertions, 383 deletions
diff --git a/src/pkg/runtime/alg.goc b/src/pkg/runtime/alg.goc
index cb8e073151..70c877ebbb 100644
--- a/src/pkg/runtime/alg.goc
+++ b/src/pkg/runtime/alg.goc
@@ -7,34 +7,7 @@ package runtime
#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)
@@ -224,67 +197,6 @@ runtime·c128equal(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)
{
@@ -301,13 +213,6 @@ runtime·algslicecopy(uintptr s, void *a, void *b)
}
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)
{
intgo alen;
@@ -349,13 +254,6 @@ runtime·strcopy(uintptr s, void *a, void *b)
}
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)
{
USED(s);
@@ -383,13 +281,6 @@ runtime·intercopy(uintptr s, void *a, void *b)
}
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)
{
USED(s);
@@ -416,15 +307,6 @@ runtime·nilintercopy(uintptr s, void *a, void *b)
((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
@@ -437,31 +319,46 @@ runtime·noequal(bool *eq, uintptr s, void *a, void *b)
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.
@@ -483,15 +380,14 @@ runtime·hashinit(void)
(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)
@@ -525,28 +421,3 @@ runtime·equal(Type *t, ...)
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;
-}
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index a4a79bd904..d2c6e30469 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -890,24 +890,22 @@ TEXT runtime·stackguard(SB),NOSPLIT,$0-8
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
@@ -958,29 +956,29 @@ finalize:
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.
@@ -2269,40 +2267,10 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4
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
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 4ddfdb71c4..19e9f1d3a2 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -954,24 +954,22 @@ TEXT runtime·stackguard(SB),NOSPLIT,$0-16
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
@@ -1022,29 +1020,29 @@ finalize:
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.
@@ -2308,40 +2306,10 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4
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
diff --git a/src/pkg/runtime/asm_amd64p32.s b/src/pkg/runtime/asm_amd64p32.s
index 0756272e24..f2a1f2a0bc 100644
--- a/src/pkg/runtime/asm_amd64p32.s
+++ b/src/pkg/runtime/asm_amd64p32.s
@@ -1181,40 +1181,10 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4
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
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 4866afd4dc..406a426078 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -1269,40 +1269,10 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $-4-4
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
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index 385ea19eac..01b47e17af 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -71,12 +71,6 @@ func testSchedLocalQueueSteal()
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
diff --git a/src/pkg/runtime/hashmap.go b/src/pkg/runtime/hashmap.go
index d181f9c930..0b4bb7d71c 100644
--- a/src/pkg/runtime/hashmap.go
+++ b/src/pkg/runtime/hashmap.go
@@ -259,7 +259,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
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 {
@@ -307,7 +307,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
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 {
@@ -349,7 +349,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
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 {
@@ -399,7 +399,7 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
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 {
@@ -508,7 +508,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
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)
@@ -664,7 +664,7 @@ next:
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
}
@@ -804,7 +804,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
}
// 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
@@ -905,7 +905,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
}
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
diff --git a/src/pkg/runtime/hashmap_fast.go b/src/pkg/runtime/hashmap_fast.go
index 5055af4a7b..6176c842dd 100644
--- a/src/pkg/runtime/hashmap_fast.go
+++ b/src/pkg/runtime/hashmap_fast.go
@@ -23,7 +23,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
// 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 {
@@ -67,7 +67,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
// 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 {
@@ -111,7 +111,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
// 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 {
@@ -155,7 +155,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
// 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 {
@@ -254,7 +254,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
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 {
@@ -356,7 +356,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
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 {
diff --git a/src/pkg/runtime/iface.goc b/src/pkg/runtime/iface.goc
index b5f5815275..ec89746470 100644
--- a/src/pkg/runtime/iface.goc
+++ b/src/pkg/runtime/iface.goc
@@ -487,17 +487,16 @@ ifacehash1(void *data, Type *t, uintptr h)
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
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 22551bda36..e6354d7e9c 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -633,7 +633,7 @@ enum
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*);
@@ -651,15 +651,19 @@ enum {
};
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*);
diff --git a/src/pkg/runtime/stubs.go b/src/pkg/runtime/stubs.go
index fa1fa859c8..30638d1af8 100644
--- a/src/pkg/runtime/stubs.go
+++ b/src/pkg/runtime/stubs.go
@@ -120,3 +120,27 @@ func golock(x *lock)
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)
+}