Commit 0c22e441 by Ian Lance Taylor

compiler, runtime: drop size arguments to hash/equal functions

    
    Drop the size arguments for the hash/equal functions stored in type
    descriptors.  Types know what size they are.  To make this work,
    generate hash/equal functions for types that can use an identity
    comparison but are not a standard size and alignment.
    
    Drop the multiplications by 33 in the generated hash code and the
    reflect package hash code.  They are not necessary since we started
    passing a seed value around, as the seed includes the hash of the
    earlier values.
    
    Copy the algorithms for standard types from the Go 1.7 runtime,
    replacing the C functions.
    
    Reviewed-on: https://go-review.googlesource.com/34983

From-SVN: r244256
parent 8462d909
189ea81cc758e000325fd6cca7882c252d33f8f0 f439989e483b7c2eada6ddcf6e730a791cce603f
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -5335,7 +5335,6 @@ Binary_expression::lower_array_comparison(Gogo* gogo, ...@@ -5335,7 +5335,6 @@ Binary_expression::lower_array_comparison(Gogo* gogo,
Expression_list* args = new Expression_list(); Expression_list* args = new Expression_list();
args->push_back(this->operand_address(inserter, this->left_)); args->push_back(this->operand_address(inserter, this->left_));
args->push_back(this->operand_address(inserter, this->right_)); args->push_back(this->operand_address(inserter, this->right_));
args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE));
Expression* ret = Expression::make_call(func, args, false, loc); Expression* ret = Expression::make_call(func, args, false, loc);
......
...@@ -2343,7 +2343,7 @@ Gogo::clear_file_scope() ...@@ -2343,7 +2343,7 @@ Gogo::clear_file_scope()
// parse tree is lowered. // parse tree is lowered.
void void
Gogo::queue_specific_type_function(Type* type, Named_type* name, Gogo::queue_specific_type_function(Type* type, Named_type* name, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype,
const std::string& equal_name, const std::string& equal_name,
...@@ -2351,7 +2351,7 @@ Gogo::queue_specific_type_function(Type* type, Named_type* name, ...@@ -2351,7 +2351,7 @@ Gogo::queue_specific_type_function(Type* type, Named_type* name,
{ {
go_assert(!this->specific_type_functions_are_written_); go_assert(!this->specific_type_functions_are_written_);
go_assert(!this->in_global_scope()); go_assert(!this->in_global_scope());
Specific_type_function* tsf = new Specific_type_function(type, name, Specific_type_function* tsf = new Specific_type_function(type, name, size,
hash_name, hash_name,
hash_fntype, hash_fntype,
equal_name, equal_name,
...@@ -2386,7 +2386,7 @@ Specific_type_functions::type(Type* t) ...@@ -2386,7 +2386,7 @@ Specific_type_functions::type(Type* t)
case Type::TYPE_NAMED: case Type::TYPE_NAMED:
{ {
Named_type* nt = t->named_type(); Named_type* nt = t->named_type();
if (!t->compare_is_identity(this->gogo_) && t->is_comparable()) if (t->needs_specific_type_functions(this->gogo_))
t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn); t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn);
// If this is a struct type, we don't want to make functions // If this is a struct type, we don't want to make functions
...@@ -2420,7 +2420,7 @@ Specific_type_functions::type(Type* t) ...@@ -2420,7 +2420,7 @@ Specific_type_functions::type(Type* t)
case Type::TYPE_STRUCT: case Type::TYPE_STRUCT:
case Type::TYPE_ARRAY: case Type::TYPE_ARRAY:
if (!t->compare_is_identity(this->gogo_) && t->is_comparable()) if (t->needs_specific_type_functions(this->gogo_))
t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn); t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn);
break; break;
...@@ -2443,7 +2443,7 @@ Gogo::write_specific_type_functions() ...@@ -2443,7 +2443,7 @@ Gogo::write_specific_type_functions()
{ {
Specific_type_function* tsf = this->specific_type_functions_.back(); Specific_type_function* tsf = this->specific_type_functions_.back();
this->specific_type_functions_.pop_back(); this->specific_type_functions_.pop_back();
tsf->type->write_specific_type_functions(this, tsf->name, tsf->type->write_specific_type_functions(this, tsf->name, tsf->size,
tsf->hash_name, tsf->hash_name,
tsf->hash_fntype, tsf->hash_fntype,
tsf->equal_name, tsf->equal_name,
......
...@@ -563,7 +563,7 @@ class Gogo ...@@ -563,7 +563,7 @@ class Gogo
// used when a type-specific function is needed when not at the top // used when a type-specific function is needed when not at the top
// level. // level.
void void
queue_specific_type_function(Type* type, Named_type* name, queue_specific_type_function(Type* type, Named_type* name, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype,
const std::string& equal_name, const std::string& equal_name,
...@@ -824,17 +824,18 @@ class Gogo ...@@ -824,17 +824,18 @@ class Gogo
{ {
Type* type; Type* type;
Named_type* name; Named_type* name;
int64_t size;
std::string hash_name; std::string hash_name;
Function_type* hash_fntype; Function_type* hash_fntype;
std::string equal_name; std::string equal_name;
Function_type* equal_fntype; Function_type* equal_fntype;
Specific_type_function(Type* atype, Named_type* aname, Specific_type_function(Type* atype, Named_type* aname, int64_t asize,
const std::string& ahash_name, const std::string& ahash_name,
Function_type* ahash_fntype, Function_type* ahash_fntype,
const std::string& aequal_name, const std::string& aequal_name,
Function_type* aequal_fntype) Function_type* aequal_fntype)
: type(atype), name(aname), hash_name(ahash_name), : type(atype), name(aname), size(asize), hash_name(ahash_name),
hash_fntype(ahash_fntype), equal_name(aequal_name), hash_fntype(ahash_fntype), equal_name(aequal_name),
equal_fntype(aequal_fntype) equal_fntype(aequal_fntype)
{ } { }
......
...@@ -975,6 +975,10 @@ class Type ...@@ -975,6 +975,10 @@ class Type
bool bool
is_backend_type_size_known(Gogo*); is_backend_type_size_known(Gogo*);
// Return whether the type needs specially built type functions.
bool
needs_specific_type_functions(Gogo*);
// Get the hash and equality functions for a type. // Get the hash and equality functions for a type.
void void
type_functions(Gogo*, Named_type* name, Function_type* hash_fntype, type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
...@@ -983,7 +987,7 @@ class Type ...@@ -983,7 +987,7 @@ class Type
// Write the hash and equality type functions. // Write the hash and equality type functions.
void void
write_specific_type_functions(Gogo*, Named_type*, write_specific_type_functions(Gogo*, Named_type*, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype,
const std::string& equal_name, const std::string& equal_name,
...@@ -1206,11 +1210,18 @@ class Type ...@@ -1206,11 +1210,18 @@ class Type
// Build the hash and equality type functions for a type which needs // Build the hash and equality type functions for a type which needs
// specific functions. // specific functions.
void void
specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype, specific_type_functions(Gogo*, Named_type*, int64_t size,
Function_type* hash_fntype,
Function_type* equal_fntype, Named_object** hash_fn, Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn); Named_object** equal_fn);
void void
write_identity_hash(Gogo*, int64_t size);
void
write_identity_equal(Gogo*, int64_t size);
void
write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype, write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype,
Function_type* equal_fntype); Function_type* equal_fntype);
......
...@@ -446,10 +446,6 @@ runtime_files = \ ...@@ -446,10 +446,6 @@ runtime_files = \
runtime/go-setenv.c \ runtime/go-setenv.c \
runtime/go-signal.c \ runtime/go-signal.c \
runtime/go-strslice.c \ runtime/go-strslice.c \
runtime/go-type-complex.c \
runtime/go-type-float.c \
runtime/go-type-identity.c \
runtime/go-type-string.c \
runtime/go-typedesc-equal.c \ runtime/go-typedesc-equal.c \
runtime/go-unsafe-new.c \ runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \ runtime/go-unsafe-newarray.c \
......
...@@ -196,13 +196,12 @@ am__objects_5 = aeshash.lo go-assert.lo go-breakpoint.lo go-caller.lo \ ...@@ -196,13 +196,12 @@ am__objects_5 = aeshash.lo go-assert.lo go-breakpoint.lo go-caller.lo \
go-memcmp.lo go-memequal.lo go-memmove.lo go-nanotime.lo \ go-memcmp.lo go-memequal.lo go-memmove.lo go-nanotime.lo \
go-now.lo go-new.lo go-nosys.lo go-reflect-call.lo \ go-now.lo go-new.lo go-nosys.lo go-reflect-call.lo \
go-runtime-error.lo go-setenv.lo go-signal.lo go-strslice.lo \ go-runtime-error.lo go-setenv.lo go-signal.lo go-strslice.lo \
go-type-complex.lo go-type-float.lo go-type-identity.lo \ go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \
go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \ go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \ env_posix.lo heapdump.lo mcache.lo mcentral.lo \
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \ $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \ panic.lo parfor.lo print.lo proc.lo runtime_c.lo thread.lo \
msize.lo panic.lo parfor.lo print.lo proc.lo runtime_c.lo \ $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
$(am__objects_4) $(am__objects_4)
am_libgo_llgo_la_OBJECTS = $(am__objects_5) am_libgo_llgo_la_OBJECTS = $(am__objects_5)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
...@@ -793,10 +792,6 @@ runtime_files = \ ...@@ -793,10 +792,6 @@ runtime_files = \
runtime/go-setenv.c \ runtime/go-setenv.c \
runtime/go-signal.c \ runtime/go-signal.c \
runtime/go-strslice.c \ runtime/go-strslice.c \
runtime/go-type-complex.c \
runtime/go-type-float.c \
runtime/go-type-identity.c \
runtime/go-type-string.c \
runtime/go-typedesc-equal.c \ runtime/go-typedesc-equal.c \
runtime/go-unsafe-new.c \ runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \ runtime/go-unsafe-newarray.c \
...@@ -1479,10 +1474,6 @@ distclean-compile: ...@@ -1479,10 +1474,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-complex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-float.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
...@@ -1745,34 +1736,6 @@ go-strslice.lo: runtime/go-strslice.c ...@@ -1745,34 +1736,6 @@ go-strslice.lo: runtime/go-strslice.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
go-type-complex.lo: runtime/go-type-complex.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-complex.lo -MD -MP -MF $(DEPDIR)/go-type-complex.Tpo -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-complex.Tpo $(DEPDIR)/go-type-complex.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-complex.c' object='go-type-complex.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
go-type-float.lo: runtime/go-type-float.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-float.lo -MD -MP -MF $(DEPDIR)/go-type-float.Tpo -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-float.Tpo $(DEPDIR)/go-type-float.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-float.c' object='go-type-float.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
go-type-identity.lo: runtime/go-type-identity.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-identity.c' object='go-type-identity.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
go-type-string.lo: runtime/go-type-string.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-string.lo -MD -MP -MF $(DEPDIR)/go-type-string.Tpo -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-string.Tpo $(DEPDIR)/go-type-string.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-string.c' object='go-type-string.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
go-typedesc-equal.lo: runtime/go-typedesc-equal.c go-typedesc-equal.lo: runtime/go-typedesc-equal.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typedesc-equal.lo -MD -MP -MF $(DEPDIR)/go-typedesc-equal.Tpo -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typedesc-equal.lo -MD -MP -MF $(DEPDIR)/go-typedesc-equal.Tpo -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typedesc-equal.Tpo $(DEPDIR)/go-typedesc-equal.Plo @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typedesc-equal.Tpo $(DEPDIR)/go-typedesc-equal.Plo
......
...@@ -254,8 +254,8 @@ type rtype struct { ...@@ -254,8 +254,8 @@ type rtype struct {
size uintptr size uintptr
hash uint32 // hash of type; avoids computation in hash tables hash uint32 // hash of type; avoids computation in hash tables
hashfn func(unsafe.Pointer, uintptr, uintptr) uintptr // hash function hashfn func(unsafe.Pointer, uintptr) uintptr // hash function
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function equalfn func(unsafe.Pointer, unsafe.Pointer) bool // equality function
gc unsafe.Pointer // garbage collection data gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful string *string // string form; unnecessary but undeniably useful
...@@ -2203,23 +2203,20 @@ func StructOf(fields []StructField) Type { ...@@ -2203,23 +2203,20 @@ func StructOf(fields []StructField) Type {
typ.gc = unsafe.Pointer(&gc[0]) typ.gc = unsafe.Pointer(&gc[0])
} }
typ.hashfn = func(p unsafe.Pointer, seed, size uintptr) uintptr { typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
ret := seed ret := seed
for i, ft := range typ.fields { for _, ft := range typ.fields {
if i > 0 {
ret *= 33
}
o := unsafe.Pointer(uintptr(p) + ft.offset) o := unsafe.Pointer(uintptr(p) + ft.offset)
ret = ft.typ.hashfn(o, ret, ft.typ.size) ret = ft.typ.hashfn(o, ret)
} }
return ret return ret
} }
typ.equalfn = func(p, q unsafe.Pointer, size uintptr) bool { typ.equalfn = func(p, q unsafe.Pointer) bool {
for _, ft := range typ.fields { for _, ft := range typ.fields {
pi := unsafe.Pointer(uintptr(p) + ft.offset) pi := unsafe.Pointer(uintptr(p) + ft.offset)
qi := unsafe.Pointer(uintptr(q) + ft.offset) qi := unsafe.Pointer(uintptr(q) + ft.offset)
if !ft.typ.equalfn(pi, qi, ft.typ.size) { if !ft.typ.equalfn(pi, qi) {
return false return false
} }
} }
...@@ -2348,19 +2345,18 @@ func ArrayOf(count int, elem Type) Type { ...@@ -2348,19 +2345,18 @@ func ArrayOf(count int, elem Type) Type {
array.kind &^= kindDirectIface array.kind &^= kindDirectIface
array.hashfn = func(p unsafe.Pointer, seed, size uintptr) uintptr { array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
ret := seed ret := seed
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
ret *= 33 ret = typ.hashfn(p, ret)
ret = typ.hashfn(p, ret, typ.size)
p = unsafe.Pointer(uintptr(p) + typ.size) p = unsafe.Pointer(uintptr(p) + typ.size)
} }
return ret return ret
} }
array.equalfn = func(p1, p2 unsafe.Pointer, size uintptr) bool { array.equalfn = func(p1, p2 unsafe.Pointer) bool {
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if !typ.equalfn(p1, p2, typ.size) { if !typ.equalfn(p1, p2) {
return false return false
} }
p1 = unsafe.Pointer(uintptr(p1) + typ.size) p1 = unsafe.Pointer(uintptr(p1) + typ.size)
......
...@@ -12,8 +12,30 @@ import ( ...@@ -12,8 +12,30 @@ import (
// For gccgo, use go:linkname to rename compiler-called functions to // For gccgo, use go:linkname to rename compiler-called functions to
// themselves, so that the compiler will export them. // themselves, so that the compiler will export them.
// //
//go:linkname memhash0 runtime.memhash0
//go:linkname memhash8 runtime.memhash8
//go:linkname memhash16 runtime.memhash16
//go:linkname memhash32 runtime.memhash32
//go:linkname memhash64 runtime.memhash64
//go:linkname memhash128 runtime.memhash128
//go:linkname strhash runtime.strhash
//go:linkname f32hash runtime.f32hash
//go:linkname f64hash runtime.f64hash
//go:linkname c64hash runtime.c64hash
//go:linkname c128hash runtime.c128hash
//go:linkname interhash runtime.interhash //go:linkname interhash runtime.interhash
//go:linkname nilinterhash runtime.nilinterhash //go:linkname nilinterhash runtime.nilinterhash
//go:linkname memequal0 runtime.memequal0
//go:linkname memequal8 runtime.memequal8
//go:linkname memequal16 runtime.memequal16
//go:linkname memequal32 runtime.memequal32
//go:linkname memequal64 runtime.memequal64
//go:linkname memequal128 runtime.memequal128
//go:linkname strequal runtime.strequal
//go:linkname f32equal runtime.f32equal
//go:linkname f64equal runtime.f64equal
//go:linkname c64equal runtime.c64equal
//go:linkname c128equal runtime.c128equal
//go:linkname interequal runtime.interequal //go:linkname interequal runtime.interequal
//go:linkname nilinterequal runtime.nilinterequal //go:linkname nilinterequal runtime.nilinterequal
//go:linkname efaceeq runtime.efaceeq //go:linkname efaceeq runtime.efaceeq
...@@ -32,6 +54,25 @@ const ( ...@@ -32,6 +54,25 @@ const (
c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503) c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503)
) )
func memhash0(p unsafe.Pointer, h uintptr) uintptr {
return h
}
func memhash8(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 1)
}
func memhash16(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 2)
}
func memhash32(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 4)
}
func memhash64(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 8)
}
func memhash128(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 16)
}
var useAeshash bool var useAeshash bool
// in C code // in C code
...@@ -46,6 +87,50 @@ func aeshashstr(p unsafe.Pointer, h uintptr) uintptr { ...@@ -46,6 +87,50 @@ func aeshashstr(p unsafe.Pointer, h uintptr) uintptr {
return aeshashbody(unsafe.Pointer(ps.str), h, uintptr(ps.len), aeskeysched[:]) return aeshashbody(unsafe.Pointer(ps.str), h, uintptr(ps.len), aeskeysched[:])
} }
func strhash(a unsafe.Pointer, h uintptr) uintptr {
x := (*stringStruct)(a)
return memhash(x.str, h, uintptr(x.len))
}
// 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.
func f32hash(p unsafe.Pointer, h uintptr) uintptr {
f := *(*float32)(p)
switch {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
default:
return memhash(p, h, 4)
}
}
func f64hash(p unsafe.Pointer, h uintptr) uintptr {
f := *(*float64)(p)
switch {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
default:
return memhash(p, h, 8)
}
}
func c64hash(p unsafe.Pointer, h uintptr) uintptr {
x := (*[2]float32)(p)
return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
}
func c128hash(p unsafe.Pointer, h uintptr) uintptr {
x := (*[2]float64)(p)
return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
}
func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
a := (*iface)(p) a := (*iface)(p)
tab := a.tab tab := a.tab
...@@ -58,13 +143,13 @@ func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { ...@@ -58,13 +143,13 @@ func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
panic(errorString("hash of unhashable type " + *t.string)) panic(errorString("hash of unhashable type " + *t.string))
} }
if isDirectIface(t) { if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) return c1 * fn(unsafe.Pointer(&a.data), h^c0)
} else { } else {
return c1 * fn(a.data, h^c0, t.size) return c1 * fn(a.data, h^c0)
} }
} }
func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
a := (*eface)(p) a := (*eface)(p)
t := a._type t := a._type
if t == nil { if t == nil {
...@@ -75,20 +160,51 @@ func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { ...@@ -75,20 +160,51 @@ func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
panic(errorString("hash of unhashable type " + *t.string)) panic(errorString("hash of unhashable type " + *t.string))
} }
if isDirectIface(t) { if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) return c1 * fn(unsafe.Pointer(&a.data), h^c0)
} else { } else {
return c1 * fn(a.data, h^c0, t.size) return c1 * fn(a.data, h^c0)
} }
} }
func memequal0(p, q unsafe.Pointer) bool {
return true
}
func memequal8(p, q unsafe.Pointer) bool {
return *(*int8)(p) == *(*int8)(q)
}
func memequal16(p, q unsafe.Pointer) bool {
return *(*int16)(p) == *(*int16)(q)
}
func memequal32(p, q unsafe.Pointer) bool {
return *(*int32)(p) == *(*int32)(q)
}
func memequal64(p, q unsafe.Pointer) bool {
return *(*int64)(p) == *(*int64)(q)
}
func memequal128(p, q unsafe.Pointer) bool {
return *(*[2]int64)(p) == *(*[2]int64)(q)
}
func f32equal(p, q unsafe.Pointer) bool {
return *(*float32)(p) == *(*float32)(q)
}
func f64equal(p, q unsafe.Pointer) bool {
return *(*float64)(p) == *(*float64)(q)
}
func c64equal(p, q unsafe.Pointer) bool {
return *(*complex64)(p) == *(*complex64)(q)
}
func c128equal(p, q unsafe.Pointer) bool {
return *(*complex128)(p) == *(*complex128)(q)
}
func strequal(p, q unsafe.Pointer) bool {
return *(*string)(p) == *(*string)(q)
}
func interequal(p, q unsafe.Pointer, size uintptr) bool { func interequal(p, q unsafe.Pointer, size uintptr) bool {
return ifaceeq(*(*iface)(p), *(*iface)(q)) return ifaceeq(*(*iface)(p), *(*iface)(q))
} }
func nilinterequal(p, q unsafe.Pointer, size uintptr) bool { func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
return efaceeq(*(*eface)(p), *(*eface)(q)) return efaceeq(*(*eface)(p), *(*eface)(q))
} }
func efaceeq(x, y eface) bool { func efaceeq(x, y eface) bool {
t := x._type t := x._type
if !eqtype(t, y._type) { if !eqtype(t, y._type) {
...@@ -104,9 +220,8 @@ func efaceeq(x, y eface) bool { ...@@ -104,9 +220,8 @@ func efaceeq(x, y eface) bool {
if isDirectIface(t) { if isDirectIface(t) {
return x.data == y.data return x.data == y.data
} }
return eq(x.data, y.data, t.size) return eq(x.data, y.data)
} }
func ifaceeq(x, y iface) bool { func ifaceeq(x, y iface) bool {
xtab := x.tab xtab := x.tab
if xtab == nil && y.tab == nil { if xtab == nil && y.tab == nil {
...@@ -126,7 +241,7 @@ func ifaceeq(x, y iface) bool { ...@@ -126,7 +241,7 @@ func ifaceeq(x, y iface) bool {
if isDirectIface(t) { if isDirectIface(t) {
return x.data == y.data return x.data == y.data
} }
return eq(x.data, y.data, t.size) return eq(x.data, y.data)
} }
func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool { func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool {
...@@ -144,7 +259,7 @@ func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool { ...@@ -144,7 +259,7 @@ func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool {
if isDirectIface(t) { if isDirectIface(t) {
return x.data == p return x.data == p
} }
return eq(x.data, p, t.size) return eq(x.data, p)
} }
func ifaceefaceeq(x iface, y eface) bool { func ifaceefaceeq(x iface, y eface) bool {
...@@ -165,7 +280,7 @@ func ifaceefaceeq(x iface, y eface) bool { ...@@ -165,7 +280,7 @@ func ifaceefaceeq(x iface, y eface) bool {
if isDirectIface(xt) { if isDirectIface(xt) {
return x.data == y.data return x.data == y.data
} }
return eq(x.data, y.data, xt.size) return eq(x.data, y.data)
} }
func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool { func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool {
...@@ -182,7 +297,7 @@ func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool { ...@@ -182,7 +297,7 @@ func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool {
if isDirectIface(t) { if isDirectIface(t) {
return x.data == p return x.data == p
} }
return eq(x.data, p, t.size) return eq(x.data, p)
} }
func eqstring(x, y string) bool { func eqstring(x, y string) bool {
...@@ -213,13 +328,47 @@ func cmpstring(x, y string) int { ...@@ -213,13 +328,47 @@ func cmpstring(x, y string) int {
return 0 return 0
} }
// For the unsafe.Pointer type descriptor in libgo/runtime/go-unsafe-pointer.c.
func pointerhash(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, unsafe.Sizeof(unsafe.Pointer))
}
func pointerequal(p, q unsafe.Pointer) bool {
return *(*unsafe.Pointer)(p) == *(*unsafe.Pointer)(q)
}
// Force the creation of function descriptors for equality and hash // Force the creation of function descriptors for equality and hash
// functions. These will be referenced directly by the compiler. // functions. These will be referenced directly by the compiler.
var _ = memhash var _ = memhash
var _ = memhash0
var _ = memhash8
var _ = memhash16
var _ = memhash32
var _ = memhash64
var _ = memhash128
var _ = strhash
var _ = f32hash
var _ = f64hash
var _ = c64hash
var _ = c128hash
var _ = interhash var _ = interhash
var _ = interequal
var _ = nilinterhash var _ = nilinterhash
var _ = memequal0
var _ = memequal8
var _ = memequal16
var _ = memequal32
var _ = memequal64
var _ = memequal128
var _ = f32equal
var _ = f64equal
var _ = c64equal
var _ = c128equal
var _ = strequal
var _ = interequal
var _ = nilinterequal var _ = nilinterequal
var _ = pointerhash
var _ = pointerequal
const hashRandomBytes = sys.PtrSize / 4 * 64 const hashRandomBytes = sys.PtrSize / 4 * 64
......
...@@ -300,7 +300,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { ...@@ -300,7 +300,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
} }
hashfn := t.key.hashfn hashfn := t.key.hashfn
equalfn := t.key.equalfn equalfn := t.key.equalfn
hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -322,7 +322,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { ...@@ -322,7 +322,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
if t.indirectkey { if t.indirectkey {
k = *((*unsafe.Pointer)(k)) k = *((*unsafe.Pointer)(k))
} }
if equalfn(key, k, uintptr(t.keysize)) { if equalfn(key, k) {
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
if t.indirectvalue { if t.indirectvalue {
v = *((*unsafe.Pointer)(v)) v = *((*unsafe.Pointer)(v))
...@@ -355,7 +355,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) ...@@ -355,7 +355,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
} }
hashfn := t.key.hashfn hashfn := t.key.hashfn
equalfn := t.key.equalfn equalfn := t.key.equalfn
hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize))) b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -377,7 +377,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) ...@@ -377,7 +377,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
if t.indirectkey { if t.indirectkey {
k = *((*unsafe.Pointer)(k)) k = *((*unsafe.Pointer)(k))
} }
if equalfn(key, k, uintptr(t.keysize)) { if equalfn(key, k) {
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
if t.indirectvalue { if t.indirectvalue {
v = *((*unsafe.Pointer)(v)) v = *((*unsafe.Pointer)(v))
...@@ -402,7 +402,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe ...@@ -402,7 +402,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
} }
hashfn := t.key.hashfn hashfn := t.key.hashfn
equalfn := t.key.equalfn equalfn := t.key.equalfn
hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize))) b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -424,7 +424,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe ...@@ -424,7 +424,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
if t.indirectkey { if t.indirectkey {
k = *((*unsafe.Pointer)(k)) k = *((*unsafe.Pointer)(k))
} }
if equalfn(key, k, uintptr(t.keysize)) { if equalfn(key, k) {
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
if t.indirectvalue { if t.indirectvalue {
v = *((*unsafe.Pointer)(v)) v = *((*unsafe.Pointer)(v))
...@@ -477,7 +477,7 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { ...@@ -477,7 +477,7 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
hashfn := t.key.hashfn hashfn := t.key.hashfn
equalfn := t.key.equalfn equalfn := t.key.equalfn
hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(key, uintptr(h.hash0))
if h.buckets == nil { if h.buckets == nil {
h.buckets = newarray(t.bucket, 1) h.buckets = newarray(t.bucket, 1)
...@@ -512,7 +512,7 @@ again: ...@@ -512,7 +512,7 @@ again:
if t.indirectkey { if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2)) k2 = *((*unsafe.Pointer)(k2))
} }
if !equalfn(key, k2, uintptr(t.keysize)) { if !equalfn(key, k2) {
continue continue
} }
// already have a mapping for key. Update it. // already have a mapping for key. Update it.
...@@ -592,7 +592,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { ...@@ -592,7 +592,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
hashfn := t.key.hashfn hashfn := t.key.hashfn
equalfn := t.key.equalfn equalfn := t.key.equalfn
hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(key, uintptr(h.hash0))
bucket := hash & (uintptr(1)<<h.B - 1) bucket := hash & (uintptr(1)<<h.B - 1)
if h.oldbuckets != nil { if h.oldbuckets != nil {
growWork(t, h, bucket) growWork(t, h, bucket)
...@@ -612,7 +612,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { ...@@ -612,7 +612,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
if t.indirectkey { if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2)) k2 = *((*unsafe.Pointer)(k2))
} }
if !equalfn(key, k2, uintptr(t.keysize)) { if !equalfn(key, k2) {
continue continue
} }
memclr(k, uintptr(t.keysize)) memclr(k, uintptr(t.keysize))
...@@ -760,10 +760,10 @@ next: ...@@ -760,10 +760,10 @@ next:
if t.indirectkey { if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2)) k2 = *((*unsafe.Pointer)(k2))
} }
if t.reflexivekey || equalfn(k2, k2, uintptr(t.keysize)) { if t.reflexivekey || equalfn(k2, k2) {
// If the item in the oldbucket is not destined for // If the item in the oldbucket is not destined for
// the current new bucket in the iteration, skip it. // the current new bucket in the iteration, skip it.
hash := hashfn(k2, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(k2, uintptr(h.hash0))
if hash&(uintptr(1)<<it.B-1) != checkBucket { if hash&(uintptr(1)<<it.B-1) != checkBucket {
continue continue
} }
...@@ -797,7 +797,7 @@ next: ...@@ -797,7 +797,7 @@ next:
if t.indirectkey { if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2)) k2 = *((*unsafe.Pointer)(k2))
} }
if t.reflexivekey || equalfn(k2, k2, uintptr(t.keysize)) { if t.reflexivekey || equalfn(k2, k2) {
// Check the current hash table for the data. // Check the current hash table for the data.
// This code handles the case where the key // This code handles the case where the key
// has been deleted, updated, or deleted and reinserted. // has been deleted, updated, or deleted and reinserted.
...@@ -913,9 +913,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { ...@@ -913,9 +913,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
} }
// Compute hash to make our evacuation decision (whether we need // Compute hash to make our evacuation decision (whether we need
// to send this key/value to bucket x or bucket y). // to send this key/value to bucket x or bucket y).
hash := hashfn(k2, uintptr(h.hash0), uintptr(t.keysize)) hash := hashfn(k2, uintptr(h.hash0))
if h.flags&iterator != 0 { if h.flags&iterator != 0 {
if !t.reflexivekey && !equalfn(k2, k2, uintptr(t.keysize)) { if !t.reflexivekey && !equalfn(k2, k2) {
// If key != key (NaNs), then the hash could be (and probably // If key != key (NaNs), then the hash could be (and probably
// will be) entirely different from the old hash. Moreover, // will be) entirely different from the old hash. Moreover,
// it isn't reproducible. Reproducibility is required in the // it isn't reproducible. Reproducibility is required in the
......
...@@ -25,7 +25,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { ...@@ -25,7 +25,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
// One-bucket table. No need to hash. // One-bucket table. No need to hash.
b = (*bmap)(h.buckets) b = (*bmap)(h.buckets)
} else { } else {
hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -70,7 +70,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { ...@@ -70,7 +70,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
// One-bucket table. No need to hash. // One-bucket table. No need to hash.
b = (*bmap)(h.buckets) b = (*bmap)(h.buckets)
} else { } else {
hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -115,7 +115,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { ...@@ -115,7 +115,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
// One-bucket table. No need to hash. // One-bucket table. No need to hash.
b = (*bmap)(h.buckets) b = (*bmap)(h.buckets)
} else { } else {
hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -160,7 +160,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { ...@@ -160,7 +160,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
// One-bucket table. No need to hash. // One-bucket table. No need to hash.
b = (*bmap)(h.buckets) b = (*bmap)(h.buckets)
} else { } else {
hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -260,7 +260,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { ...@@ -260,7 +260,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
return unsafe.Pointer(&zeroVal[0]) return unsafe.Pointer(&zeroVal[0])
} }
dohash: dohash:
hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
...@@ -363,7 +363,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { ...@@ -363,7 +363,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
return unsafe.Pointer(&zeroVal[0]), false return unsafe.Pointer(&zeroVal[0]), false
} }
dohash: dohash:
hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0), uintptr(t.keysize)) hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1 m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil { if c := h.oldbuckets; c != nil {
......
...@@ -16,8 +16,8 @@ type _type struct { ...@@ -16,8 +16,8 @@ type _type struct {
size uintptr size uintptr
hash uint32 hash uint32
hashfn func(unsafe.Pointer, uintptr, uintptr) uintptr hashfn func(unsafe.Pointer, uintptr) uintptr
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool equalfn func(unsafe.Pointer, unsafe.Pointer) bool
gc unsafe.Pointer gc unsafe.Pointer
string *string string *string
......
/* go-type-complex.c -- hash and equality complex functions.
Copyright 2012 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 <complex.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include "runtime.h"
#include "go-type.h"
/* Hash function for float types. */
uintptr_t
__go_type_hash_complex (const void *vkey, uintptr_t seed, uintptr_t key_size)
{
if (key_size == 8)
{
const complex float *cfp;
complex float cf;
float cfr;
float cfi;
uint64_t fi;
cfp = (const complex float *) vkey;
cf = *cfp;
cfr = crealf (cf);
cfi = cimagf (cf);
if (isinf (cfr) || isinf (cfi))
return seed;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */
if (isnan (cfr) || isnan (cfi))
return runtime_fastrand1 ();
/* Avoid negative zero. */
if (cfr == 0 && cfi == 0)
return seed;
else if (cfr == 0)
cf = cfi * I;
else if (cfi == 0)
cf = cfr;
memcpy (&fi, &cf, 8);
return (uintptr_t) cfi ^ seed;
}
else if (key_size == 16)
{
const complex double *cdp;
complex double cd;
double cdr;
double cdi;
uint64_t di[2];
cdp = (const complex double *) vkey;
cd = *cdp;
cdr = creal (cd);
cdi = cimag (cd);
if (isinf (cdr) || isinf (cdi))
return seed;
if (isnan (cdr) || isnan (cdi))
return runtime_fastrand1 ();
/* Avoid negative zero. */
if (cdr == 0 && cdi == 0)
return seed;
else if (cdr == 0)
cd = cdi * I;
else if (cdi == 0)
cd = cdr;
memcpy (&di, &cd, 16);
return di[0] ^ di[1] ^ seed;
}
else
runtime_throw ("__go_type_hash_complex: invalid complex size");
}
const FuncVal __go_type_hash_complex_descriptor =
{ (void *) __go_type_hash_complex };
/* Equality function for complex types. */
_Bool
__go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 8)
{
const complex float *cfp1;
const complex float *cfp2;
cfp1 = (const complex float *) vk1;
cfp2 = (const complex float *) vk2;
return *cfp1 == *cfp2;
}
else if (key_size == 16)
{
const complex double *cdp1;
const complex double *cdp2;
cdp1 = (const complex double *) vk1;
cdp2 = (const complex double *) vk2;
return *cdp1 == *cdp2;
}
else
runtime_throw ("__go_type_equal_complex: invalid complex size");
}
const FuncVal __go_type_equal_complex_descriptor =
{ (void *) __go_type_equal_complex };
/* go-type-float.c -- hash and equality float functions.
Copyright 2012 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 <math.h>
#include <stdint.h>
#include "runtime.h"
#include "go-type.h"
/* Hash function for float types. */
uintptr_t
__go_type_hash_float (const void *vkey, uintptr_t seed, uintptr_t key_size)
{
if (key_size == 4)
{
const float *fp;
float f;
uint32_t si;
fp = (const float *) vkey;
f = *fp;
if (isinf (f) || f == 0)
return seed;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */
if (isnan (f))
return runtime_fastrand1 ();
memcpy (&si, vkey, 4);
return (uintptr_t) si ^ seed;
}
else if (key_size == 8)
{
const double *dp;
double d;
uint64_t di;
dp = (const double *) vkey;
d = *dp;
if (isinf (d) || d == 0)
return seed;
if (isnan (d))
return runtime_fastrand1 ();
memcpy (&di, vkey, 8);
return (uintptr_t) di ^ seed;
}
else
runtime_throw ("__go_type_hash_float: invalid float size");
}
const FuncVal __go_type_hash_float_descriptor =
{ (void *) __go_type_hash_float };
/* Equality function for float types. */
_Bool
__go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 4)
{
const float *fp1;
const float *fp2;
fp1 = (const float *) vk1;
fp2 = (const float *) vk2;
return *fp1 == *fp2;
}
else if (key_size == 8)
{
const double *dp1;
const double *dp2;
dp1 = (const double *) vk1;
dp2 = (const double *) vk2;
return *dp1 == *dp2;
}
else
runtime_throw ("__go_type_equal_float: invalid float size");
}
const FuncVal __go_type_equal_float_descriptor =
{ (void *) __go_type_equal_float };
/* go-type-identity.c -- hash and equality identity functions.
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 <stddef.h>
#include "runtime.h"
#include "go-type.h"
/* The hash functions for types that can compare as identity is
written in Go. */
extern uintptr runtime_memhash(void *, uintptr, uintptr)
__asm__ (GOSYM_PREFIX "runtime.memhash");
const FuncVal __go_type_hash_identity_descriptor =
{ (void *) runtime_memhash };
/* An identity equality function for a type. This is used for types
where we can check for equality by checking that the values have
the same bits. */
_Bool
__go_type_equal_identity (const void *k1, const void *k2, uintptr_t key_size)
{
return __builtin_memcmp (k1, k2, key_size) == 0;
}
const FuncVal __go_type_equal_identity_descriptor =
{ (void *) __go_type_equal_identity };
/* go-type-string.c -- hash and equality string functions.
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"
#include "go-type.h"
#include "go-string.h"
/* A string hash function for a map. */
uintptr_t
__go_type_hash_string (const void *vkey, uintptr_t seed,
uintptr_t key_size __attribute__ ((unused)))
{
uintptr_t ret;
const String *key;
intgo len;
intgo i;
const byte *p;
ret = seed;
key = (const String *) vkey;
len = key->len;
for (i = 0, p = key->str; i < len; i++, p++)
ret = ret * 33 + *p;
return ret;
}
const FuncVal __go_type_hash_string_descriptor =
{ (void *) __go_type_hash_string };
/* A string equality function for a map. */
_Bool
__go_type_equal_string (const void *vk1, const void *vk2,
uintptr_t key_size __attribute__ ((unused)))
{
const String *k1;
const String *k2;
k1 = (const String *) vk1;
k2 = (const String *) vk2;
return __go_ptr_strings_equal (k1, k2);
}
const FuncVal __go_type_equal_string_descriptor =
{ (void *) __go_type_equal_string };
...@@ -362,24 +362,4 @@ extern _Bool ...@@ -362,24 +362,4 @@ extern _Bool
__go_type_descriptors_equal(const struct __go_type_descriptor*, __go_type_descriptors_equal(const struct __go_type_descriptor*,
const struct __go_type_descriptor*); const struct __go_type_descriptor*);
extern const FuncVal __go_type_hash_identity_descriptor;
extern _Bool __go_type_equal_identity (const void *, const void *, uintptr_t);
extern const FuncVal __go_type_equal_identity_descriptor;
extern uintptr_t __go_type_hash_string (const void *, uintptr_t, uintptr_t);
extern const FuncVal __go_type_hash_string_descriptor;
extern _Bool __go_type_equal_string (const void *, const void *, uintptr_t);
extern const FuncVal __go_type_equal_string_descriptor;
extern uintptr_t __go_type_hash_float (const void *, uintptr_t, uintptr_t);
extern const FuncVal __go_type_hash_float_descriptor;
extern _Bool __go_type_equal_float (const void *, const void *, uintptr_t);
extern const FuncVal __go_type_equal_float_descriptor;
extern uintptr_t __go_type_hash_complex (const void *, uintptr_t, uintptr_t);
extern const FuncVal __go_type_hash_complex_descriptor;
extern _Bool __go_type_equal_complex (const void *, const void *, uintptr_t);
extern const FuncVal __go_type_equal_complex_descriptor;
extern uintptr_t __go_type_hash_interface (const void *, uintptr_t, uintptr_t);
extern const FuncVal __go_type_hash_interface_descriptor;
extern _Bool __go_type_equal_interface (const void *, const void *, uintptr_t);
extern const FuncVal __go_type_equal_interface_descriptor;
#endif /* !defined(LIBGO_GO_TYPE_H) */ #endif /* !defined(LIBGO_GO_TYPE_H) */
...@@ -38,6 +38,11 @@ static const String reflection_string = ...@@ -38,6 +38,11 @@ static const String reflection_string =
const uintptr unsafe_Pointer_gc[] = {sizeof(void*), GC_APTR, 0, GC_END}; const uintptr unsafe_Pointer_gc[] = {sizeof(void*), GC_APTR, 0, GC_END};
extern const FuncVal runtime_pointerhash_descriptor
__asm__ (GOSYM_PREFIX "runtime.pointerhash$descriptor");
extern const FuncVal runtime_pointerequal_descriptor
__asm__ (GOSYM_PREFIX "runtime.pointerequal$descriptor");
const struct __go_type_descriptor unsafe_Pointer = const struct __go_type_descriptor unsafe_Pointer =
{ {
/* __code */ /* __code */
...@@ -51,9 +56,9 @@ const struct __go_type_descriptor unsafe_Pointer = ...@@ -51,9 +56,9 @@ const struct __go_type_descriptor unsafe_Pointer =
/* __hash */ /* __hash */
78501163U, 78501163U,
/* __hashfn */ /* __hashfn */
&__go_type_hash_identity_descriptor, &runtime_pointerhash_descriptor,
/* __equalfn */ /* __equalfn */
&__go_type_equal_identity_descriptor, &runtime_pointerequal_descriptor,
/* __gc */ /* __gc */
unsafe_Pointer_gc, unsafe_Pointer_gc,
/* __reflection */ /* __reflection */
...@@ -94,9 +99,9 @@ const struct __go_ptr_type pointer_unsafe_Pointer = ...@@ -94,9 +99,9 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
/* __hash */ /* __hash */
1256018616U, 1256018616U,
/* __hashfn */ /* __hashfn */
&__go_type_hash_identity_descriptor, &runtime_pointerhash_descriptor,
/* __equalfn */ /* __equalfn */
&__go_type_equal_identity_descriptor, &runtime_pointerequal_descriptor,
/* __gc */ /* __gc */
unsafe_Pointer_gc, unsafe_Pointer_gc,
/* __reflection */ /* __reflection */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment