From: Ian Lance Taylor Date: Tue, 10 Jan 2017 03:59:20 +0000 (+0000) Subject: compiler, runtime: drop size arguments to hash/equal functions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0c22e4415fe9e88acaa99e72d33f4500d557ce68;p=gcc.git 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 2bbbc0f3292..73c4d303696 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -189ea81cc758e000325fd6cca7882c252d33f8f0 +f439989e483b7c2eada6ddcf6e730a791cce603f The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 02c33203309..da721030e88 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -5335,7 +5335,6 @@ Binary_expression::lower_array_comparison(Gogo* gogo, Expression_list* args = new Expression_list(); args->push_back(this->operand_address(inserter, this->left_)); 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); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index ff82f11948f..4e2d6b46ad0 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2343,7 +2343,7 @@ Gogo::clear_file_scope() // parse tree is lowered. 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, Function_type* hash_fntype, const std::string& equal_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->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_fntype, equal_name, @@ -2386,7 +2386,7 @@ Specific_type_functions::type(Type* t) case Type::TYPE_NAMED: { 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); // If this is a struct type, we don't want to make functions @@ -2420,7 +2420,7 @@ Specific_type_functions::type(Type* t) case Type::TYPE_STRUCT: 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); break; @@ -2443,7 +2443,7 @@ Gogo::write_specific_type_functions() { Specific_type_function* tsf = this->specific_type_functions_.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_fntype, tsf->equal_name, diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 905f48d233d..7c29828231f 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -563,7 +563,7 @@ class Gogo // used when a type-specific function is needed when not at the top // level. 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, Function_type* hash_fntype, const std::string& equal_name, @@ -824,17 +824,18 @@ class Gogo { Type* type; Named_type* name; + int64_t size; std::string hash_name; Function_type* hash_fntype; std::string equal_name; 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, Function_type* ahash_fntype, const std::string& aequal_name, 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), equal_fntype(aequal_fntype) { } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index e7fe326357d..0b394c96de7 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -1425,7 +1425,9 @@ Type::make_builtin_struct_type(int nfields, ...) va_end(ap); - return Type::make_struct_type(sfl, bloc); + Struct_type* ret = Type::make_struct_type(sfl, bloc); + ret->set_is_struct_incomparable(); + return ret; } // A list of builtin named types. @@ -1488,7 +1490,6 @@ Type::make_type_descriptor_type() Typed_identifier_list *params = new Typed_identifier_list(); params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc)); params->push_back(Typed_identifier("seed", uintptr_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); Typed_identifier_list* results = new Typed_identifier_list(); results->push_back(Typed_identifier("", uintptr_type, bloc)); @@ -1499,7 +1500,6 @@ Type::make_type_descriptor_type() params = new Typed_identifier_list(); params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc)); params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); results = new Typed_identifier_list(); results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc)); @@ -1578,6 +1578,51 @@ Type::make_type_descriptor_ptr_type() return ret; } +// Return whether this type needs specially built type functions. +// This returns true for types that are comparable and either can not +// use an identity comparison, or are a non-standard size. + +bool +Type::needs_specific_type_functions(Gogo* gogo) +{ + if (!this->is_comparable()) + return false; + if (!this->compare_is_identity(gogo)) + return true; + + // We create a few predeclared types for type descriptors; they are + // really just for the backend and don't need hash or equality + // functions. + Named_type* nt = this->named_type(); + if (nt != NULL && Linemap::is_predeclared_location(nt->location())) + return false; + + int64_t size, align; + if (!this->backend_type_size(gogo, &size) + || !this->backend_type_align(gogo, &align)) + { + go_assert(saw_errors()); + return false; + } + // This switch matches the one in Type::type_functions. + switch (size) + { + case 0: + case 1: + case 2: + return align < 2; + case 4: + return align < 4; + case 8: + return align < 8; + case 16: + // 8, not 16, because of how runtime.memequal128 is written. + return align < 8; + default: + return true; + } +} + // Set *HASH_FN and *EQUAL_FN to the runtime functions which compute a // hash code for this type and which compare whether two values of // this type are equal. If NAME is not NULL it is the name of this @@ -1610,7 +1655,6 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc)); params->push_back(Typed_identifier("seed", uintptr_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); Typed_identifier_list* results = new Typed_identifier_list(); results->push_back(Typed_identifier("", uintptr_type, bloc)); @@ -1624,7 +1668,6 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, bloc)); params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); Typed_identifier_list* results = new Typed_identifier_list(); results->push_back(Typed_identifier("", Type::lookup_bool_type(), @@ -1638,8 +1681,78 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, const char* equal_fnname; if (this->compare_is_identity(gogo)) { - hash_fnname = "runtime.memhash"; - equal_fnname = "__go_type_equal_identity"; + int64_t size, align; + if (!this->backend_type_size(gogo, &size) + || !this->backend_type_align(gogo, &align)) + { + go_assert(saw_errors()); + return; + } + bool build_functions = false; + // This switch matches the one in Type::needs_specific_type_functions. + // The alignment tests are because of the memequal functions, + // which assume that the values are aligned as required for an + // integer of that size. + switch (size) + { + case 0: + hash_fnname = "runtime.memhash0"; + equal_fnname = "runtime.memequal0"; + break; + case 1: + hash_fnname = "runtime.memhash8"; + equal_fnname = "runtime.memequal8"; + break; + case 2: + if (align < 2) + build_functions = true; + else + { + hash_fnname = "runtime.memhash16"; + equal_fnname = "runtime.memequal16"; + } + break; + case 4: + if (align < 4) + build_functions = true; + else + { + hash_fnname = "runtime.memhash32"; + equal_fnname = "runtime.memequal32"; + } + break; + case 8: + if (align < 8) + build_functions = true; + else + { + hash_fnname = "runtime.memhash64"; + equal_fnname = "runtime.memequal64"; + } + break; + case 16: + // 8, not 16, because of how runtime.memequal128 is written. + if (align < 8) + build_functions = true; + else + { + hash_fnname = "runtime.memhash128"; + equal_fnname = "runtime.memequal128"; + } + break; + default: + build_functions = true; + break; + } + if (build_functions) + { + // We don't have a built-in function for a type of this size + // and alignment. Build a function to use that calls the + // generic hash/equality functions for identity, passing the size. + this->specific_type_functions(gogo, name, size, hash_fntype, + equal_fntype, hash_fn, equal_fn); + return; + } } else { @@ -1661,18 +1774,40 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, go_unreachable(); case Type::TYPE_FLOAT: - hash_fnname = "__go_type_hash_float"; - equal_fnname = "__go_type_equal_float"; + switch (this->float_type()->bits()) + { + case 32: + hash_fnname = "runtime.f32hash"; + equal_fnname = "runtime.f32equal"; + break; + case 64: + hash_fnname = "runtime.f64hash"; + equal_fnname = "runtime.f64equal"; + break; + default: + go_unreachable(); + } break; case Type::TYPE_COMPLEX: - hash_fnname = "__go_type_hash_complex"; - equal_fnname = "__go_type_equal_complex"; + switch (this->complex_type()->bits()) + { + case 64: + hash_fnname = "runtime.c64hash"; + equal_fnname = "runtime.c64equal"; + break; + case 128: + hash_fnname = "runtime.c128hash"; + equal_fnname = "runtime.c128equal"; + break; + default: + go_unreachable(); + } break; case Type::TYPE_STRING: - hash_fnname = "__go_type_hash_string"; - equal_fnname = "__go_type_equal_string"; + hash_fnname = "runtime.strhash"; + equal_fnname = "runtime.strequal"; break; case Type::TYPE_STRUCT: @@ -1680,7 +1815,7 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, // This is a struct which can not be compared using a // simple identity function. We need to build a function // for comparison. - this->specific_type_functions(gogo, name, hash_fntype, + this->specific_type_functions(gogo, name, -1, hash_fntype, equal_fntype, hash_fn, equal_fn); return; } @@ -1697,7 +1832,7 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, // This is an array which can not be compared using a // simple identity function. We need to build a // function for comparison. - this->specific_type_functions(gogo, name, hash_fntype, + this->specific_type_functions(gogo, name, -1, hash_fntype, equal_fntype, hash_fn, equal_fn); return; } @@ -1739,11 +1874,13 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, Type::Type_functions Type::type_functions_table; -// Handle a type function which is specific to a type: a struct or -// array which can not use an identity comparison. +// Handle a type function which is specific to a type: if SIZE == -1, +// this is a struct or array that can not use an identity comparison. +// Otherwise, it is a type that uses an identity comparison but is not +// one of the standard supported sizes. void -Type::specific_type_functions(Gogo* gogo, Named_type* name, +Type::specific_type_functions(Gogo* gogo, Named_type* name, int64_t size, Function_type* hash_fntype, Function_type* equal_fntype, Named_object** hash_fn, @@ -1829,11 +1966,13 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name, if (!is_defined_elsewhere) { if (gogo->in_global_scope()) - this->write_specific_type_functions(gogo, name, hash_name, hash_fntype, - equal_name, equal_fntype); + this->write_specific_type_functions(gogo, name, size, hash_name, + hash_fntype, equal_name, + equal_fntype); else - gogo->queue_specific_type_function(this, name, hash_name, hash_fntype, - equal_name, equal_fntype); + gogo->queue_specific_type_function(this, name, size, hash_name, + hash_fntype, equal_name, + equal_fntype); } } @@ -1841,7 +1980,7 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name, // written specially. void -Type::write_specific_type_functions(Gogo* gogo, Named_type* name, +Type::write_specific_type_functions(Gogo* gogo, Named_type* name, int64_t size, const std::string& hash_name, Function_type* hash_fntype, const std::string& equal_name, @@ -1862,7 +2001,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, hash_fn->func_value()->set_is_type_specific_function(); gogo->start_block(bloc); - if (name != NULL && name->real_type()->named_type() != NULL) + if (size != -1) + this->write_identity_hash(gogo, size); + else if (name != NULL && name->real_type()->named_type() != NULL) this->write_named_hash(gogo, name, hash_fntype, equal_fntype); else if (this->struct_type() != NULL) this->struct_type()->write_hash_function(gogo, name, hash_fntype, @@ -1883,7 +2024,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, equal_fn->func_value()->set_is_type_specific_function(); gogo->start_block(bloc); - if (name != NULL && name->real_type()->named_type() != NULL) + if (size != -1) + this->write_identity_equal(gogo, size); + else if (name != NULL && name->real_type()->named_type() != NULL) this->write_named_equal(gogo, name); else if (this->struct_type() != NULL) this->struct_type()->write_equal_function(gogo, name); @@ -1902,6 +2045,112 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, equal_fn->func_value()->descriptor(gogo, equal_fn); } +// Write a hash function for a type that can use an identity hash but +// is not one of the standard supported sizes. For example, this +// would be used for the type [3]byte. This builds a return statement +// that returns a call to the memhash function, passing the key and +// seed from the function arguments (already constructed before this +// is called), and the constant size. + +void +Type::write_identity_hash(Gogo* gogo, int64_t size) +{ + Location bloc = Linemap::predeclared_location(); + + Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + + Typed_identifier_list* params = new Typed_identifier_list(); + params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc)); + params->push_back(Typed_identifier("seed", uintptr_type, bloc)); + params->push_back(Typed_identifier("size", uintptr_type, bloc)); + + Typed_identifier_list* results = new Typed_identifier_list(); + results->push_back(Typed_identifier("", uintptr_type, bloc)); + + Function_type* memhash_fntype = Type::make_function_type(NULL, params, + results, bloc); + + Named_object* memhash = + Named_object::make_function_declaration("runtime.memhash", NULL, + memhash_fntype, bloc); + memhash->func_declaration_value()->set_asm_name("runtime.memhash"); + + Named_object* key_arg = gogo->lookup("key", NULL); + go_assert(key_arg != NULL); + Named_object* seed_arg = gogo->lookup("seed", NULL); + go_assert(seed_arg != NULL); + + Expression* key_ref = Expression::make_var_reference(key_arg, bloc); + Expression* seed_ref = Expression::make_var_reference(seed_arg, bloc); + Expression* size_arg = Expression::make_integer_int64(size, uintptr_type, + bloc); + Expression_list* args = new Expression_list(); + args->push_back(key_ref); + args->push_back(seed_ref); + args->push_back(size_arg); + Expression* func = Expression::make_func_reference(memhash, NULL, bloc); + Expression* call = Expression::make_call(func, args, false, bloc); + + Expression_list* vals = new Expression_list(); + vals->push_back(call); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + +// Write an equality function for a type that can use an identity +// equality comparison but is not one of the standard supported sizes. +// For example, this would be used for the type [3]byte. This builds +// a return statement that returns a call to the memequal function, +// passing the two keys from the function arguments (already +// constructed before this is called), and the constant size. + +void +Type::write_identity_equal(Gogo* gogo, int64_t size) +{ + Location bloc = Linemap::predeclared_location(); + + Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + + Typed_identifier_list* params = new Typed_identifier_list(); + params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc)); + params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc)); + params->push_back(Typed_identifier("size", uintptr_type, bloc)); + + Typed_identifier_list* results = new Typed_identifier_list(); + results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc)); + + Function_type* memequal_fntype = Type::make_function_type(NULL, params, + results, bloc); + + Named_object* memequal = + Named_object::make_function_declaration("runtime.memequal", NULL, + memequal_fntype, bloc); + memequal->func_declaration_value()->set_asm_name("runtime.memequal"); + + Named_object* key1_arg = gogo->lookup("key1", NULL); + go_assert(key1_arg != NULL); + Named_object* key2_arg = gogo->lookup("key2", NULL); + go_assert(key2_arg != NULL); + + Expression* key1_ref = Expression::make_var_reference(key1_arg, bloc); + Expression* key2_ref = Expression::make_var_reference(key2_arg, bloc); + Expression* size_arg = Expression::make_integer_int64(size, uintptr_type, + bloc); + Expression_list* args = new Expression_list(); + args->push_back(key1_ref); + args->push_back(key2_ref); + args->push_back(size_arg); + Expression* func = Expression::make_func_reference(memequal, NULL, bloc); + Expression* call = Expression::make_call(func, args, false, bloc); + + Expression_list* vals = new Expression_list(); + vals->push_back(call); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + // Write a hash function that simply calls the hash function for a // named type. This is used when one named type is defined as // another. This ensures that this case works when the other named @@ -1926,10 +2175,6 @@ Type::write_named_hash(Gogo* gogo, Named_type* name, Named_object* seed_arg = gogo->lookup("seed", NULL); go_assert(seed_arg != NULL); - // The size of the type we are going to hash. - Named_object* keysz_arg = gogo->lookup("key_size", NULL); - go_assert(keysz_arg != NULL); - Named_object* hash_fn; Named_object* equal_fn; name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype, @@ -1938,11 +2183,9 @@ Type::write_named_hash(Gogo* gogo, Named_type* name, // Call the hash function for the base type. Expression* key_ref = Expression::make_var_reference(key_arg, bloc); Expression* seed_ref = Expression::make_var_reference(seed_arg, bloc); - Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc); Expression_list* args = new Expression_list(); args->push_back(key_ref); args->push_back(seed_ref); - args->push_back(keysz_ref); Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); Expression* call = Expression::make_call(func, args, false, bloc); @@ -5410,7 +5653,6 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*, gogo->add_statement(key); // Loop over the struct fields. - bool first = true; const Struct_field_list* fields = this->fields_; for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); @@ -5419,19 +5661,6 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*, if (Gogo::is_sink_name(pf->field_name())) continue; - if (first) - first = false; - else - { - // Multiply retval by 33. - Expression* i33 = Expression::make_integer_ul(33, uintptr_type, - bloc); - ref = Expression::make_temporary_reference(retval, bloc); - Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, - ref, i33, bloc); - gogo->add_statement(s); - } - // Get a pointer to the value of this field. Expression* offset = Expression::make_struct_field_offset(this, &*pf); ref = Expression::make_temporary_reference(key, bloc); @@ -5439,10 +5668,6 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*, bloc); subkey = Expression::make_cast(key_arg_type, subkey, bloc); - // Get the size of this field. - Expression* size = Expression::make_type_info(pf->type(), - Expression::TYPE_INFO_SIZE); - // Get the hash function to use for the type of this field. Named_object* hash_fn; Named_object* equal_fn; @@ -5454,7 +5679,6 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*, Expression_list* args = new Expression_list(); args->push_back(subkey); args->push_back(ref); - args->push_back(size); Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); Expression* call = Expression::make_call(func, args, false, bloc); @@ -6295,14 +6519,6 @@ Array_type::write_hash_function(Gogo* gogo, Named_type* name, gogo->start_block(bloc); - // Multiply retval by 33. - Expression* i33 = Expression::make_integer_ul(33, uintptr_type, bloc); - - ref = Expression::make_temporary_reference(retval, bloc); - Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, ref, - i33, bloc); - gogo->add_statement(s); - // Get the hash function for the element type. Named_object* hash_fn; Named_object* equal_fn; @@ -6323,7 +6539,6 @@ Array_type::write_hash_function(Gogo* gogo, Named_type* name, Expression_list* args = new Expression_list(); args->push_back(subkey); args->push_back(ref); - args->push_back(ele_size); Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); Expression* call = Expression::make_call(func, args, false, bloc); @@ -6331,7 +6546,7 @@ Array_type::write_hash_function(Gogo* gogo, Named_type* name, Temporary_reference_expression* tref = Expression::make_temporary_reference(retval, bloc); tref->set_is_lvalue(); - s = Statement::make_assignment(tref, call, bloc); + Statement* s = Statement::make_assignment(tref, call, bloc); gogo->add_statement(s); // Increase the element pointer. diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 58d60e5a011..e9c31628ec1 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -975,6 +975,10 @@ class Type bool 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. void type_functions(Gogo*, Named_type* name, Function_type* hash_fntype, @@ -983,7 +987,7 @@ class Type // Write the hash and equality type functions. void - write_specific_type_functions(Gogo*, Named_type*, + write_specific_type_functions(Gogo*, Named_type*, int64_t size, const std::string& hash_name, Function_type* hash_fntype, const std::string& equal_name, @@ -1206,10 +1210,17 @@ class Type // Build the hash and equality type functions for a type which needs // specific functions. 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, Named_object** equal_fn); + 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, Function_type* equal_fntype); diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 93eaa9f2046..fed41117716 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -446,10 +446,6 @@ runtime_files = \ runtime/go-setenv.c \ runtime/go-signal.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-unsafe-new.c \ runtime/go-unsafe-newarray.c \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 424e41b6333..581607a96c4 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -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-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-type-complex.lo go-type-float.lo go-type-identity.lo \ - go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \ - go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \ - go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \ - mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \ - msize.lo panic.lo parfor.lo print.lo proc.lo runtime_c.lo \ - thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \ + go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \ + go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \ + env_posix.lo heapdump.lo mcache.lo mcentral.lo \ + $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \ + panic.lo parfor.lo print.lo proc.lo runtime_c.lo thread.lo \ + $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \ $(am__objects_4) am_libgo_llgo_la_OBJECTS = $(am__objects_5) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) @@ -793,10 +792,6 @@ runtime_files = \ runtime/go-setenv.c \ runtime/go-signal.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-unsafe-new.c \ runtime/go-unsafe-newarray.c \ @@ -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-signal.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-unsafe-new.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 @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 -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 @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 diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 13b326f5a8d..4f13f144327 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -254,8 +254,8 @@ type rtype struct { size uintptr hash uint32 // hash of type; avoids computation in hash tables - hashfn func(unsafe.Pointer, uintptr, uintptr) uintptr // hash function - equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function + hashfn func(unsafe.Pointer, uintptr) uintptr // hash function + equalfn func(unsafe.Pointer, unsafe.Pointer) bool // equality function gc unsafe.Pointer // garbage collection data string *string // string form; unnecessary but undeniably useful @@ -2203,23 +2203,20 @@ func StructOf(fields []StructField) Type { 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 - for i, ft := range typ.fields { - if i > 0 { - ret *= 33 - } + for _, ft := range typ.fields { o := unsafe.Pointer(uintptr(p) + ft.offset) - ret = ft.typ.hashfn(o, ret, ft.typ.size) + ret = ft.typ.hashfn(o, 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 { pi := unsafe.Pointer(uintptr(p) + 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 } } @@ -2348,19 +2345,18 @@ func ArrayOf(count int, elem Type) Type { array.kind &^= kindDirectIface - array.hashfn = func(p unsafe.Pointer, seed, size uintptr) uintptr { + array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr { ret := seed for i := 0; i < count; i++ { - ret *= 33 - ret = typ.hashfn(p, ret, typ.size) + ret = typ.hashfn(p, ret) p = unsafe.Pointer(uintptr(p) + typ.size) } 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++ { - if !typ.equalfn(p1, p2, typ.size) { + if !typ.equalfn(p1, p2) { return false } p1 = unsafe.Pointer(uintptr(p1) + typ.size) diff --git a/libgo/go/runtime/alg.go b/libgo/go/runtime/alg.go index 53312313017..426b7f6bab3 100644 --- a/libgo/go/runtime/alg.go +++ b/libgo/go/runtime/alg.go @@ -12,8 +12,30 @@ import ( // For gccgo, use go:linkname to rename compiler-called functions to // 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 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 nilinterequal runtime.nilinterequal //go:linkname efaceeq runtime.efaceeq @@ -32,6 +54,25 @@ const ( 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 // in C code @@ -46,6 +87,50 @@ func aeshashstr(p unsafe.Pointer, h uintptr) uintptr { 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 { a := (*iface)(p) tab := a.tab @@ -58,13 +143,13 @@ func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { panic(errorString("hash of unhashable type " + *t.string)) } if isDirectIface(t) { - return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) + return c1 * fn(unsafe.Pointer(&a.data), h^c0) } 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) t := a._type if t == nil { @@ -75,20 +160,51 @@ func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { panic(errorString("hash of unhashable type " + *t.string)) } if isDirectIface(t) { - return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) + return c1 * fn(unsafe.Pointer(&a.data), h^c0) } 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 { return ifaceeq(*(*iface)(p), *(*iface)(q)) } - func nilinterequal(p, q unsafe.Pointer, size uintptr) bool { return efaceeq(*(*eface)(p), *(*eface)(q)) } - func efaceeq(x, y eface) bool { t := x._type if !eqtype(t, y._type) { @@ -104,9 +220,8 @@ func efaceeq(x, y eface) bool { if isDirectIface(t) { 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 { xtab := x.tab if xtab == nil && y.tab == nil { @@ -126,7 +241,7 @@ func ifaceeq(x, y iface) bool { if isDirectIface(t) { 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 { @@ -144,7 +259,7 @@ func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool { if isDirectIface(t) { return x.data == p } - return eq(x.data, p, t.size) + return eq(x.data, p) } func ifaceefaceeq(x iface, y eface) bool { @@ -165,7 +280,7 @@ func ifaceefaceeq(x iface, y eface) bool { if isDirectIface(xt) { 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 { @@ -182,7 +297,7 @@ func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool { if isDirectIface(t) { return x.data == p } - return eq(x.data, p, t.size) + return eq(x.data, p) } func eqstring(x, y string) bool { @@ -213,13 +328,47 @@ func cmpstring(x, y string) int { 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 // functions. These will be referenced directly by the compiler. 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 _ = interequal 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 _ = pointerhash +var _ = pointerequal const hashRandomBytes = sys.PtrSize / 4 * 64 diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go index aaf4fb4d6e3..77b33f341f7 100644 --- a/libgo/go/runtime/hashmap.go +++ b/libgo/go/runtime/hashmap.go @@ -300,7 +300,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { } hashfn := t.key.hashfn equalfn := t.key.equalfn - hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize)) + hash := hashfn(key, uintptr(h.hash0)) m := uintptr(1)< -#include -#include -#include -#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 }; diff --git a/libgo/runtime/go-type-float.c b/libgo/runtime/go-type-float.c deleted file mode 100644 index ae0e3367c21..00000000000 --- a/libgo/runtime/go-type-float.c +++ /dev/null @@ -1,92 +0,0 @@ -/* 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 -#include -#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 }; diff --git a/libgo/runtime/go-type-identity.c b/libgo/runtime/go-type-identity.c deleted file mode 100644 index 842fa249bd0..00000000000 --- a/libgo/runtime/go-type-identity.c +++ /dev/null @@ -1,32 +0,0 @@ -/* 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 - -#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 }; diff --git a/libgo/runtime/go-type-string.c b/libgo/runtime/go-type-string.c deleted file mode 100644 index c7277ddb646..00000000000 --- a/libgo/runtime/go-type-string.c +++ /dev/null @@ -1,49 +0,0 @@ -/* 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 }; diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h index 2d5965c64d3..e1552548d1e 100644 --- a/libgo/runtime/go-type.h +++ b/libgo/runtime/go-type.h @@ -362,24 +362,4 @@ extern _Bool __go_type_descriptors_equal(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) */ diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c index ce82fcd4070..b98068365e1 100644 --- a/libgo/runtime/go-unsafe-pointer.c +++ b/libgo/runtime/go-unsafe-pointer.c @@ -38,6 +38,11 @@ static const String reflection_string = 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 = { /* __code */ @@ -51,9 +56,9 @@ const struct __go_type_descriptor unsafe_Pointer = /* __hash */ 78501163U, /* __hashfn */ - &__go_type_hash_identity_descriptor, + &runtime_pointerhash_descriptor, /* __equalfn */ - &__go_type_equal_identity_descriptor, + &runtime_pointerequal_descriptor, /* __gc */ unsafe_Pointer_gc, /* __reflection */ @@ -94,9 +99,9 @@ const struct __go_ptr_type pointer_unsafe_Pointer = /* __hash */ 1256018616U, /* __hashfn */ - &__go_type_hash_identity_descriptor, + &runtime_pointerhash_descriptor, /* __equalfn */ - &__go_type_equal_identity_descriptor, + &runtime_pointerequal_descriptor, /* __gc */ unsafe_Pointer_gc, /* __reflection */