summaryrefslogtreecommitdiff
path: root/erts/emulator/beam
diff options
context:
space:
mode:
authorGuilherme Andrade <g@gandrade.net>2017-04-19 00:43:37 +0100
committerGuilherme Andrade <g@gandrade.net>2017-04-19 01:25:35 +0100
commit0835f40ae25f97360dc393928796387d3cd6b16e (patch)
tree22b56cc3a6cb90d79efb394ecd1fab58e1182f8c /erts/emulator/beam
parent6124bfc9b61227a5e82f1d7273d0895e909aac6e (diff)
downloaderlang-0835f40ae25f97360dc393928796387d3cd6b16e.tar.gz
erts: Add enif_phash2 and enif_phash2_ranged
These allow one to hash VM terms from NIF code.
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/bif.c17
-rw-r--r--erts/emulator/beam/erl_nif.c20
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h4
-rw-r--r--erts/emulator/beam/erl_utils.h1
-rw-r--r--erts/emulator/beam/utils.c10
5 files changed, 41 insertions, 11 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 214de3652f..d59adc18d6 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4888,7 +4888,6 @@ BIF_RETTYPE phash2_1(BIF_ALIST_1)
BIF_RETTYPE phash2_2(BIF_ALIST_2)
{
Uint32 hash;
- Uint32 final_hash;
Uint32 range;
/* Check for special case 2^32 */
@@ -4901,23 +4900,19 @@ BIF_RETTYPE phash2_2(BIF_ALIST_2)
}
range = (Uint32) u;
}
- hash = make_hash2(BIF_ARG_1);
- if (range) {
- final_hash = hash % range; /* [0..range-1] */
- } else {
- final_hash = hash;
- }
+ hash = make_hash2_within_range(BIF_ARG_1, range);
+
/*
* Return either a small or a big. Use the heap for bigs if there is room.
*/
#if defined(ARCH_64)
- BIF_RET(make_small(final_hash));
+ BIF_RET(make_small(hash));
#else
- if (IS_USMALL(0, final_hash)) {
- BIF_RET(make_small(final_hash));
+ if (IS_USMALL(0, hash)) {
+ BIF_RET(make_small(hash));
} else {
Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
- BIF_RET(uint_to_big(final_hash, hp));
+ BIF_RET(uint_to_big(hash, hp));
}
#endif
}
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f86b9739fa..14abf461a3 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -55,6 +55,7 @@
#include "dtrace-wrapper.h"
#include "erl_process.h"
#include "erl_bif_unique.h"
+#include "erl_utils.h"
#undef ERTS_WANT_NFUNC_SCHED_INTERNALS__
#define ERTS_WANT_NFUNC_SCHED_INTERNALS__
#include "erl_nfunc_sched.h"
@@ -1213,6 +1214,25 @@ int enif_compare(Eterm lhs, Eterm rhs)
return result;
}
+#if SIZEOF_LONG < 4
+/* This *really* shouldn't happen */
+# error Incompatible long word size
+#endif
+
+unsigned long enif_phash2(Eterm term)
+{
+ return make_hash2(term) & ((1 << 27) - 1);
+}
+
+unsigned long enif_phash2_ranged(Eterm term, unsigned long range)
+{
+#if SIZEOF_LONG > 4
+ if (range > (unsigned long) UINT32_MAX)
+ range = 0;
+#endif
+ return make_hash2_within_range(term, range);
+}
+
int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, const Eterm** array)
{
Eterm* ptr;
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 01d9e386ed..8a3f9165d9 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -47,6 +47,8 @@ ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term,
ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, const ERL_NIF_TERM** array));
ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
ERL_NIF_API_FUNC_DECL(int,enif_compare,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(unsigned long,enif_phash2,(ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(unsigned long,enif_phash2_ranged,(ERL_NIF_TERM term, unsigned long));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
@@ -208,6 +210,8 @@ ERL_NIF_API_FUNC_DECL(int, enif_compare_monitors,(const ErlNifMonitor*,const Erl
# define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell)
# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical)
# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare)
+# define enif_phash2 ERL_NIF_API_FUNC_MACRO(enif_phash2)
+# define enif_phash2_ranged ERL_NIF_API_FUNC_MACRO(enif_phash2_ranged)
# define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary)
# define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg)
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 47289a0af1..75578c26d6 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -119,6 +119,7 @@ Sint erts_list_length(Eterm);
int erts_is_builtin(Eterm, Eterm, int);
Uint32 block_hash(byte *, unsigned, Uint32);
Uint32 make_hash2(Eterm);
+Uint32 make_hash2_within_range(Eterm, Uint32);
Uint32 make_hash(Eterm);
Uint32 make_internal_hash(Eterm);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 8f3f48f38f..72c59b33c6 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1552,6 +1552,16 @@ make_hash2(Eterm term)
}
}
+Uint32
+make_hash2_within_range(Eterm term, Uint32 range)
+{
+ Uint32 hash = make_hash2(term);
+ if (range)
+ return hash % range; /* [0..range-1] */
+ else
+ return hash; /* Special case: 2**32 */
+}
+
/* Term hash function for internal use.
*
* Limitation #1: Is not "portable" in any way between different VM instances.