Remove the use of make_hash2

We were being rather naughty relying on the ability to resolve symbols
in the executable that loads the NIF. Apparently Windows has a much
different NIF loading system which prevents this from working. Given
that the patch for exposing enif_phash was never merged we're solving
the issue by removing the need from hashing terms in the NIF.

This new approach simply hashes the term in Erlang and passes the
calculated value in the NIF call. We then just store the calculated
value along with the key and value as before.

COUCHDB-2750
diff --git a/c_src/khash.c b/c_src/khash.c
index a2364b0..8081c3b 100644
--- a/c_src/khash.c
+++ b/c_src/khash.c
@@ -4,6 +4,7 @@
 
 #include <assert.h>
 #include <string.h>
+#include <stdint.h>
 
 #include "erl_nif.h"
 #include "hash.h"
@@ -27,6 +28,7 @@
 
 typedef struct
 {
+    unsigned int hval;
     ErlNifEnv* env;
     ERL_NIF_TERM key;
     ERL_NIF_TERM val;
@@ -51,13 +53,6 @@
 } khash_iter_t;
 
 
-// This is actually an internal Erlang VM function that
-// we're being a bit hacky to get access to. There's a
-// pending patch to expose this in the NIF API in newer
-// Erlangs.
-unsigned int make_hash2(ERL_NIF_TERM term);
-
-
 static inline ERL_NIF_TERM
 make_atom(ErlNifEnv* env, const char* name)
 {
@@ -145,7 +140,7 @@
 khash_hash_fun(const void* obj)
 {
     khnode_t* node = (khnode_t*) obj;
-    return (hash_val_t) make_hash2(node->key);
+    return (hash_val_t) node->hval;
 }
 
 
@@ -284,9 +279,10 @@
 
 
 static inline hnode_t*
-khash_lookup_int(ErlNifEnv* env, ERL_NIF_TERM key, khash_t* khash)
+khash_lookup_int(ErlNifEnv* env, uint32_t hv, ERL_NIF_TERM key, khash_t* khash)
 {
     khnode_t node;
+    node.hval = hv;
     node.env = env;
     node.key = key;
     return kl_hash_lookup(khash->h, &node);
@@ -298,12 +294,12 @@
 {
     khash_priv* priv = enif_priv_data(env);
     khash_t* khash = NULL;
-    void* res = NULL;
+    uint32_t hval;
     hnode_t* entry;
     khnode_t* node;
     ERL_NIF_TERM ret;
 
-    if(argc != 2) {
+    if(argc != 3) {
         return enif_make_badarg(env);
     }
 
@@ -317,7 +313,11 @@
         return enif_make_badarg(env);
     }
 
-    entry = khash_lookup_int(env, argv[1], khash);
+    if(!enif_get_uint(env, argv[1], &hval)) {
+        return enif_make_badarg(env);
+    }
+
+    entry = khash_lookup_int(env, hval, argv[2], khash);
     if(entry == NULL) {
         ret = priv->atom_not_found;
     } else {
@@ -335,12 +335,12 @@
 {
     khash_priv* priv = enif_priv_data(env);
     khash_t* khash = NULL;
-    void* res = NULL;
+    uint32_t hval;
     hnode_t* entry;
     khnode_t* node;
     ERL_NIF_TERM ret;
 
-    if(argc != 3) {
+    if(argc != 4) {
         return enif_make_badarg(env);
     }
 
@@ -354,9 +354,13 @@
         return enif_make_badarg(env);
     }
 
-    entry = khash_lookup_int(env, argv[1], khash);
+    if(!enif_get_uint(env, argv[1], &hval)) {
+        return enif_make_badarg(env);
+    }
+
+    entry = khash_lookup_int(env, hval, argv[2], khash);
     if(entry == NULL) {
-        ret = argv[2];
+        ret = argv[3];
     } else {
         node = (khnode_t*) kl_hnode_getkey(entry);
         ret = enif_make_copy(env, node->val);
@@ -371,10 +375,59 @@
 {
     khash_priv* priv = enif_priv_data(env);
     khash_t* khash = NULL;
-    void* res = NULL;
+    uint32_t hval;
     hnode_t* entry;
     khnode_t* node;
 
+    if(argc != 4) {
+        return enif_make_badarg(env);
+    }
+
+    if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
+        return enif_make_badarg(env);
+    }
+
+    khash = (khash_t*) res;
+
+    if(!check_pid(env, khash)) {
+        return enif_make_badarg(env);
+    }
+
+    if(!enif_get_uint(env, argv[1], &hval)) {
+        return enif_make_badarg(env);
+    }
+
+    entry = khash_lookup_int(env, hval, argv[2], khash);
+    if(entry == NULL) {
+        entry = khnode_alloc(NULL);
+        node = (khnode_t*) kl_hnode_getkey(entry);
+        node->hval = hval;
+        node->key = enif_make_copy(node->env, argv[2]);
+        node->val = enif_make_copy(node->env, argv[3]);
+        kl_hash_insert(khash->h, entry, node);
+    } else {
+        node = (khnode_t*) kl_hnode_getkey(entry);
+        enif_clear_env(node->env);
+        node->key = enif_make_copy(node->env, argv[2]);
+        node->val = enif_make_copy(node->env, argv[3]);
+    }
+
+    khash->gen += 1;
+
+    return priv->atom_ok;
+}
+
+
+static ERL_NIF_TERM
+khash_del(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+    khash_priv* priv = enif_priv_data(env);
+    khash_t* khash = NULL;
+    void* res = NULL;
+    uint32_t hval;
+    hnode_t* entry;
+    ERL_NIF_TERM ret;
+
     if(argc != 3) {
         return enif_make_badarg(env);
     }
@@ -389,50 +442,11 @@
         return enif_make_badarg(env);
     }
 
-    entry = khash_lookup_int(env, argv[1], khash);
-    if(entry == NULL) {
-        entry = khnode_alloc(NULL);
-        node = (khnode_t*) kl_hnode_getkey(entry);
-        node->key = enif_make_copy(node->env, argv[1]);
-        node->val = enif_make_copy(node->env, argv[2]);
-        kl_hash_insert(khash->h, entry, node);
-    } else {
-        node = (khnode_t*) kl_hnode_getkey(entry);
-        enif_clear_env(node->env);
-        node->key = enif_make_copy(node->env, argv[1]);
-        node->val = enif_make_copy(node->env, argv[2]);
-    }
-
-    khash->gen += 1;
-
-    return priv->atom_ok;
-}
-
-
-static ERL_NIF_TERM
-khash_del(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
-    khash_priv* priv = enif_priv_data(env);
-    khash_t* khash = NULL;
-    void* res = NULL;
-    hnode_t* entry;
-    ERL_NIF_TERM ret;
-
-    if(argc != 2) {
+    if(!enif_get_uint(env, argv[1], &hval)) {
         return enif_make_badarg(env);
     }
 
-    if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
-        return enif_make_badarg(env);
-    }
-
-    khash = (khash_t*) res;
-
-    if(!check_pid(env, khash)) {
-        return enif_make_badarg(env);
-    }
-
-    entry = khash_lookup_int(env, argv[1], khash);
+    entry = khash_lookup_int(env, hval, argv[2], khash);
     if(entry == NULL) {
         ret = priv->atom_not_found;
     } else {
@@ -623,10 +637,10 @@
     {"new", 1, khash_new},
     {"to_list", 1, khash_to_list},
     {"clear", 1, khash_clear},
-    {"lookup", 2, khash_lookup},
-    {"get", 3, khash_get},
-    {"put", 3, khash_put},
-    {"del", 2, khash_del},
+    {"lookup_int", 3, khash_lookup},
+    {"get_int", 4, khash_get},
+    {"put_int", 4, khash_put},
+    {"del_int", 3, khash_del},
     {"size", 1, khash_size},
     {"iter", 1, khash_iter},
     {"iter_next", 1, khash_iter_next}
diff --git a/src/khash.erl b/src/khash.erl
index 7b474bd..daaf5ea 100644
--- a/src/khash.erl
+++ b/src/khash.erl
@@ -69,8 +69,8 @@
 
 
 -spec lookup(khash(), any()) -> {value, any()} | not_found.
-lookup(_Hash, _Key) ->
-    ?NOT_LOADED.
+lookup(Hash, Key) ->
+    lookup_int(Hash, erlang:phash2(Key), Key).
 
 
 -spec get(khash(), any()) -> any().
@@ -79,18 +79,18 @@
 
 
 -spec get(khash(), any(), any()) -> any().
-get(_Hash, _Key, _Default) ->
-    ?NOT_LOADED.
+get(Hash, Key, Default) ->
+    get_int(Hash, erlang:phash2(Key), Key, Default).
 
 
 -spec put(khash(), any(), any()) -> ok.
-put(_Hash, _Key, _Value) ->
-    ?NOT_LOADED.
+put(Hash, Key, Value) ->
+    put_int(Hash, erlang:phash2(Key), Key, Value).
 
 
 -spec del(khash(), any()) -> ok.
-del(_Hash, _Key) ->
-    ?NOT_LOADED.
+del(Hash, Key) ->
+    del_int(Hash, erlang:phash2(Key), Key).
 
 
 -spec size(khash()) -> non_neg_integer().
@@ -137,5 +137,21 @@
     erlang:load_nif(filename:join(PrivDir, "khash"), 0).
 
 
+lookup_int(_Hash, _HashValue, _Key) ->
+    ?NOT_LOADED.
+
+
+get_int(_Hash, _HashValue, _Key, _Default) ->
+    ?NOT_LOADED.
+
+
+put_int(_Hash, _HashValue, _Key, _Value) ->
+    ?NOT_LOADED.
+
+
+del_int(_Hash, _HashValue, _Key) ->
+    ?NOT_LOADED.
+
+
 not_loaded(Line) ->
     erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).