Skip to content

Commit

Permalink
Merge branch 'egil/erts/remove-broken-hash/OTP-13827'
Browse files Browse the repository at this point in the history
* egil/erts/remove-broken-hash/OTP-13827:
  Update test cases for erlang:hash/2 removal
  mnesia: Remove mnesia_frag_old_hash hash module
  stdlib: Produce correct warning for erlang:hash/2
  erts: Remove erlang:hash/2 from documentation
  erts: Remove broken hash from Erlang
  • Loading branch information
psyeugenic committed Jan 26, 2017
2 parents 7ac0749 + 52097fa commit 9153f7a
Show file tree
Hide file tree
Showing 25 changed files with 143 additions and 745 deletions.
23 changes: 0 additions & 23 deletions erts/doc/src/erlang.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1954,26 +1954,6 @@ os_prompt%</pre>
</desc>
</func>

<func>
<name name="hash" arity="2"/>
<fsummary>Hash function (deprecated).</fsummary>
<desc>
<p>Returns a hash value for <c><anno>Term</anno></c> within the range
<c>1..<anno>Range</anno></c>. The maximum range is 1..2^27-1.</p>
<warning>
<p><em>This BIF is deprecated, as the hash value can differ on
different architectures.</em> The hash values for integer
terms &gt; 2^27 and large binaries are
poor. The BIF is retained for backward compatibility
reasons (it can have been used to hash records into a file),
but all new code is to use one of the BIFs
<seealso marker="#phash/2"><c>erlang:phash/2</c></seealso> or
<seealso marker="#phash2/1"><c>erlang:phash2/1,2</c></seealso>
instead.</p>
</warning>
</desc>
</func>

<func>
<name name="hd" arity="1"/>
<fsummary>Head of a list.</fsummary>
Expand Down Expand Up @@ -3818,9 +3798,6 @@ RealSystem = system + MissedSystem</code>
<c><anno>Term</anno></c> within the range
<c>1..<anno>Range</anno></c>. The maximum value for
<c><anno>Range</anno></c> is 2^32.</p>
<p>This BIF can be used instead of the old deprecated BIF
<c>erlang:hash/2</c>, as it calculates better hashes for
all data types, but consider using <c>phash2/1,2</c> instead.</p>
</desc>
</func>

Expand Down
19 changes: 0 additions & 19 deletions erts/emulator/beam/bif.c
Original file line number Diff line number Diff line change
Expand Up @@ -4723,25 +4723,6 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)

/**********************************************************************/

BIF_RETTYPE hash_2(BIF_ALIST_2)
{
Uint32 hash;
Sint range;

if (is_not_small(BIF_ARG_2)) {
BIF_ERROR(BIF_P, BADARG);
}
if ((range = signed_val(BIF_ARG_2)) <= 0) { /* [1..MAX_SMALL] */
BIF_ERROR(BIF_P, BADARG);
}
#if defined(ARCH_64)
if (range > ((1L << 27) - 1))
BIF_ERROR(BIF_P, BADARG);
#endif
hash = make_broken_hash(BIF_ARG_1);
BIF_RET(make_small(1 + (hash % range))); /* [1..range] */
}

BIF_RETTYPE phash_2(BIF_ALIST_2)
{
Uint32 hash;
Expand Down
6 changes: 0 additions & 6 deletions erts/emulator/beam/bif.tab
Original file line number Diff line number Diff line change
Expand Up @@ -670,9 +670,3 @@ gcbif erlang:ceil/1
bif math:floor/1
bif math:ceil/1
bif math:fmod/2

#
# Obsolete
#

bif erlang:hash/2
1 change: 0 additions & 1 deletion erts/emulator/beam/erl_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ int erts_fit_in_bits_int32(Sint32);
int erts_fit_in_bits_uint(Uint);
Sint erts_list_length(Eterm);
int erts_is_builtin(Eterm, Eterm, int);
Uint32 make_broken_hash(Eterm);
Uint32 block_hash(byte *, unsigned, Uint32);
Uint32 make_hash2(Eterm);
Uint32 make_hash(Eterm);
Expand Down
264 changes: 5 additions & 259 deletions erts/emulator/beam/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,7 @@ erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length,
/* make a hash index from an erlang term */

/*
** There are three hash functions.
** make_broken_hash: the one used for backward compatibility
** is called from the bif erlang:hash/2. Should never be used
** as it a) hashes only a part of binaries, b) hashes bignums really poorly,
** c) hashes bignums differently on different endian processors and d) hashes
** small integers with different weights on different bytes.
** There are two hash functions.
**
** make_hash: A hash function that will give the same values for the same
** terms regardless of the internal representation. Small integers are
Expand Down Expand Up @@ -1045,6 +1040,10 @@ Uint32 make_hash(Eterm term_arg)
DESTROY_WSTACK(stack);
return hash;

#undef MAKE_HASH_TUPLE_OP
#undef MAKE_HASH_TERM_ARRAY_OP
#undef MAKE_HASH_CDR_PRE_OP
#undef MAKE_HASH_CDR_POST_OP
#undef UINT32_HASH_STEP
#undef UINT32_HASH_RET
}
Expand Down Expand Up @@ -1954,259 +1953,6 @@ make_internal_hash(Eterm term)
#undef HCONST
#undef MIX


Uint32 make_broken_hash(Eterm term)
{
Uint32 hash = 0;
DECLARE_WSTACK(stack);
unsigned op;
tail_recur:
op = tag_val_def(term);
for (;;) {
switch (op) {
case NIL_DEF:
hash = hash*FUNNY_NUMBER3 + 1;
break;
case ATOM_DEF:
hash = hash*FUNNY_NUMBER1 +
(atom_tab(atom_val(term))->slot.bucket.hvalue);
break;
case SMALL_DEF:
#if defined(ARCH_64)
{
Sint y1 = signed_val(term);
Uint y2 = y1 < 0 ? -(Uint)y1 : y1;
Uint32 y3 = (Uint32) (y2 >> 32);
int arity = 1;

#if defined(WORDS_BIGENDIAN)
if (!IS_SSMALL28(y1))
{ /* like a bignum */
Uint32 y4 = (Uint32) y2;
hash = hash*FUNNY_NUMBER2 + ((y4 << 16) | (y4 >> 16));
if (y3) {
hash = hash*FUNNY_NUMBER2 + ((y3 << 16) | (y3 >> 16));
arity++;
}
hash = hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity;
} else {
hash = hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff);
}
#else
if (!IS_SSMALL28(y1))
{ /* like a bignum */
hash = hash*FUNNY_NUMBER2 + ((Uint32) y2);
if (y3)
{
hash = hash*FUNNY_NUMBER2 + y3;
arity++;
}
hash = hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity;
} else {
hash = hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff);
}
#endif
}
#else
hash = hash*FUNNY_NUMBER2 + unsigned_val(term);
#endif
break;

case BINARY_DEF:
{
size_t sz = binary_size(term);
size_t i = (sz < 15) ? sz : 15;

hash = hash_binary_bytes(term, i, hash);
hash = hash*FUNNY_NUMBER4 + sz;
break;
}

case EXPORT_DEF:
{
Export* ep = *((Export **) (export_val(term) + 1));

hash = hash * FUNNY_NUMBER11 + ep->info.mfa.arity;
hash = hash*FUNNY_NUMBER1 +
(atom_tab(atom_val(ep->info.mfa.module))->slot.bucket.hvalue);
hash = hash*FUNNY_NUMBER1 +
(atom_tab(atom_val(ep->info.mfa.function))->slot.bucket.hvalue);
break;
}

case FUN_DEF:
{
ErlFunThing* funp = (ErlFunThing *) fun_val(term);
Uint num_free = funp->num_free;

hash = hash * FUNNY_NUMBER10 + num_free;
hash = hash*FUNNY_NUMBER1 +
(atom_tab(atom_val(funp->fe->module))->slot.bucket.hvalue);
hash = hash*FUNNY_NUMBER2 + funp->fe->old_index;
hash = hash*FUNNY_NUMBER2 + funp->fe->old_uniq;
if (num_free > 0) {
if (num_free > 1) {
WSTACK_PUSH3(stack, (UWord) &funp->env[1], (num_free-1), MAKE_HASH_TERM_ARRAY_OP);
}
term = funp->env[0];
goto tail_recur;
}
break;
}

case PID_DEF:
hash = hash*FUNNY_NUMBER5 + internal_pid_number(term);
break;
case EXTERNAL_PID_DEF:
hash = hash*FUNNY_NUMBER5 + external_pid_number(term);
break;
case PORT_DEF:
hash = hash*FUNNY_NUMBER9 + internal_port_number(term);
break;
case EXTERNAL_PORT_DEF:
hash = hash*FUNNY_NUMBER9 + external_port_number(term);
break;
case REF_DEF:
hash = hash*FUNNY_NUMBER9 + internal_ref_numbers(term)[0];
break;
case EXTERNAL_REF_DEF:
hash = hash*FUNNY_NUMBER9 + external_ref_numbers(term)[0];
break;
case FLOAT_DEF:
{
FloatDef ff;
GET_DOUBLE(term, ff);
if (ff.fd == 0.0f) {
/* ensure positive 0.0 */
ff.fd = erts_get_positive_zero_float();
}
hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]);
}
break;
case MAKE_HASH_CDR_PRE_OP:
term = (Eterm) WSTACK_POP(stack);
if (is_not_list(term)) {
WSTACK_PUSH(stack, (UWord) MAKE_HASH_CDR_POST_OP);
goto tail_recur;
}
/*fall through*/
case LIST_DEF:
{
Eterm* list = list_val(term);
WSTACK_PUSH2(stack, (UWord) CDR(list),
(UWord) MAKE_HASH_CDR_PRE_OP);
term = CAR(list);
goto tail_recur;
}

case MAKE_HASH_CDR_POST_OP:
hash *= FUNNY_NUMBER8;
break;

case BIG_DEF:
{
Eterm* ptr = big_val(term);
int is_neg = BIG_SIGN(ptr);
Uint arity = BIG_ARITY(ptr);
Uint i = arity;
ptr++;
#if D_EXP == 16
/* hash over 32 bit LE */

while(i--) {
hash = hash*FUNNY_NUMBER2 + *ptr++;
}
#elif D_EXP == 32

#if defined(WORDS_BIGENDIAN)
while(i--) {
Uint d = *ptr++;
hash = hash*FUNNY_NUMBER2 + ((d << 16) | (d >> 16));
}
#else
while(i--) {
hash = hash*FUNNY_NUMBER2 + *ptr++;
}
#endif

#elif D_EXP == 64
{
Uint32 h = 0, l;
#if defined(WORDS_BIGENDIAN)
while(i--) {
Uint d = *ptr++;
l = d & 0xffffffff;
h = d >> 32;
hash = hash*FUNNY_NUMBER2 + ((l << 16) | (l >> 16));
if (h || i)
hash = hash*FUNNY_NUMBER2 + ((h << 16) | (h >> 16));
}
#else
while(i--) {
Uint d = *ptr++;
l = d & 0xffffffff;
h = d >> 32;
hash = hash*FUNNY_NUMBER2 + l;
if (h || i)
hash = hash*FUNNY_NUMBER2 + h;
}
#endif
/* adjust arity to match 32 bit mode */
arity = (arity << 1) - (h == 0);
}

#else
#error "unsupported D_EXP size"
#endif
hash = hash * (is_neg ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity;
}
break;

case MAP_DEF:
hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term);
break;
case TUPLE_DEF:
{
Eterm* ptr = tuple_val(term);
Uint arity = arityval(*ptr);

WSTACK_PUSH3(stack, (UWord) arity, (UWord) (ptr+1), (UWord) arity);
op = MAKE_HASH_TUPLE_OP;
}/*fall through*/
case MAKE_HASH_TUPLE_OP:
case MAKE_HASH_TERM_ARRAY_OP:
{
Uint i = (Uint) WSTACK_POP(stack);
Eterm* ptr = (Eterm*) WSTACK_POP(stack);
if (i != 0) {
term = *ptr;
WSTACK_PUSH3(stack, (UWord)(ptr+1), (UWord) i-1, (UWord) op);
goto tail_recur;
}
if (op == MAKE_HASH_TUPLE_OP) {
Uint32 arity = (UWord) WSTACK_POP(stack);
hash = hash*FUNNY_NUMBER9 + arity;
}
break;
}

default:
erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_broken_hash\n");
return 0;
}
if (WSTACK_ISEMPTY(stack)) break;
op = (Uint) WSTACK_POP(stack);
}

DESTROY_WSTACK(stack);
return hash;

#undef MAKE_HASH_TUPLE_OP
#undef MAKE_HASH_TERM_ARRAY_OP
#undef MAKE_HASH_CDR_PRE_OP
#undef MAKE_HASH_CDR_POST_OP
}

static Eterm
do_allocate_logger_message(Eterm gleader, Eterm **hp, ErlOffHeap **ohp,
ErlHeapFragment **bp, Process **p, Uint sz)
Expand Down
2 changes: 0 additions & 2 deletions erts/emulator/test/binary_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
%%

-module(binary_SUITE).
-compile({nowarn_deprecated_function, {erlang,hash,2}}).

%% Tests binaries and the BIFs:
%% list_to_binary/1
Expand Down Expand Up @@ -392,7 +391,6 @@ test_hash(List) ->
Bin = list_to_binary(List),
Sbin = make_sub_binary(List),
Unaligned = make_unaligned_sub_binary(Sbin),
test_hash_1(Bin, Sbin, Unaligned, fun erlang:hash/2),
test_hash_1(Bin, Sbin, Unaligned, fun erlang:phash/2),
test_hash_1(Bin, Sbin, Unaligned, fun erlang:phash2/2).

Expand Down
Loading

0 comments on commit 9153f7a

Please sign in to comment.