Introduced tags for NJS_DATA type.

NJS_DATA is designed to contain arbitrary opaque pointers.
Tags are used to distinguish different opaque pointers.
diff --git a/src/njs.h b/src/njs.h
index 88cacfb..82a570f 100644
--- a/src/njs.h
+++ b/src/njs.h
@@ -341,11 +341,9 @@
 NJS_EXPORT void njs_value_undefined_set(njs_value_t *value);
 NJS_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn);
 NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num);
-NJS_EXPORT void njs_value_data_set(njs_value_t *value, void *data);
 
 NJS_EXPORT uint8_t njs_value_bool(const njs_value_t *value);
 NJS_EXPORT double njs_value_number(const njs_value_t *value);
-NJS_EXPORT void *njs_value_data(const njs_value_t *value);
 NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value);
 
 NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop);
diff --git a/src/njs_crypto.c b/src/njs_crypto.c
index 9989ef1..71e2d0b 100644
--- a/src/njs_crypto.c
+++ b/src/njs_crypto.c
@@ -184,7 +184,7 @@
 
     alg->init(&dgst->u);
 
-    njs_set_data(&hash->value, dgst);
+    njs_set_data(&hash->value, dgst, NJS_DATA_TAG_CRYPTO_HASH);
     njs_set_object_value(&vm->retval, hash);
 
     return NJS_OK;
@@ -196,6 +196,7 @@
     njs_index_t unused)
 {
     njs_str_t     data;
+    njs_value_t   *this;
     njs_digest_t  *dgst;
 
     if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
@@ -203,19 +204,16 @@
         return NJS_ERROR;
     }
 
-    if (njs_slow_path(!njs_is_object_value(&args[0]))) {
-        njs_type_error(vm, "\"this\" is not an object_value");
-        return NJS_ERROR;
-    }
+    this = njs_argument(args, 0);
 
-    if (njs_slow_path(!njs_is_data(njs_object_value(&args[0])))) {
-        njs_type_error(vm, "value of \"this\" is not a data type");
+    if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HASH))) {
+        njs_type_error(vm, "\"this\" is not a hash object");
         return NJS_ERROR;
     }
 
     njs_string_get(&args[1], &data);
 
-    dgst = njs_value_data(njs_object_value(&args[0]));
+    dgst = njs_object_data(this);
 
     if (njs_slow_path(dgst->alg == NULL)) {
         njs_error(vm, "Digest already called");
@@ -224,7 +222,7 @@
 
     dgst->alg->update(&dgst->u, data.start, data.length);
 
-    vm->retval = args[0];
+    vm->retval = *this;
 
     return NJS_OK;
 }
@@ -237,6 +235,7 @@
     u_char            digest[32], *p;
     njs_int_t         ret;
     njs_str_t         enc_name, str;
+    njs_value_t       *this;
     njs_digest_t      *dgst;
     njs_hash_alg_t    *alg;
     njs_crypto_enc_t  *enc;
@@ -246,13 +245,10 @@
         return NJS_ERROR;
     }
 
-    if (njs_slow_path(!njs_is_object_value(&args[0]))) {
-        njs_type_error(vm, "\"this\" is not an object_value");
-        return NJS_ERROR;
-    }
+    this = njs_argument(args, 0);
 
-    if (njs_slow_path(!njs_is_data(njs_object_value(&args[0])))) {
-        njs_type_error(vm, "value of \"this\" is not a data type");
+    if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HASH))) {
+        njs_type_error(vm, "\"this\" is not a hash object");
         return NJS_ERROR;
     }
 
@@ -267,7 +263,7 @@
         }
     }
 
-    dgst = njs_value_data(njs_object_value(&args[0]));
+    dgst = njs_object_data(this);
 
     if (njs_slow_path(dgst->alg == NULL)) {
         njs_error(vm, "Digest already called");
@@ -465,7 +461,7 @@
         return NJS_ERROR;
     }
 
-    njs_set_data(&hmac->value, ctx);
+    njs_set_data(&hmac->value, ctx, NJS_DATA_TAG_CRYPTO_HMAC);
     njs_set_object_value(&vm->retval, hmac);
 
     return NJS_OK;
@@ -476,27 +472,25 @@
 njs_hmac_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_str_t   data;
-    njs_hmac_t  *ctx;
+    njs_str_t    data;
+    njs_hmac_t   *ctx;
+    njs_value_t  *this;
 
     if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
         njs_type_error(vm, "data must be a string");
         return NJS_ERROR;
     }
 
-    if (njs_slow_path(!njs_is_object_value(&args[0]))) {
-        njs_type_error(vm, "\"this\" is not an object_value");
-        return NJS_ERROR;
-    }
+    this = njs_argument(args, 0);
 
-    if (njs_slow_path(!njs_is_data(njs_object_value(&args[0])))) {
-        njs_type_error(vm, "value of \"this\" is not a data type");
+    if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HMAC))) {
+        njs_type_error(vm, "\"this\" is not a hash object");
         return NJS_ERROR;
     }
 
     njs_string_get(&args[1], &data);
 
-    ctx = njs_value_data(njs_object_value(&args[0]));
+    ctx = njs_object_data(this);
 
     if (njs_slow_path(ctx->alg == NULL)) {
         njs_error(vm, "Digest already called");
@@ -505,7 +499,7 @@
 
     ctx->alg->update(&ctx->u, data.start, data.length);
 
-    vm->retval = args[0];
+    vm->retval = *this;
 
     return NJS_OK;
 }
@@ -519,6 +513,7 @@
     njs_str_t         enc_name, str;
     njs_int_t         ret;
     njs_hmac_t        *ctx;
+    njs_value_t       *this;
     njs_hash_alg_t    *alg;
     njs_crypto_enc_t  *enc;
 
@@ -527,13 +522,10 @@
         return NJS_ERROR;
     }
 
-    if (njs_slow_path(!njs_is_object_value(&args[0]))) {
-        njs_type_error(vm, "\"this\" is not an object_value");
-        return NJS_ERROR;
-    }
+    this = njs_argument(args, 0);
 
-    if (njs_slow_path(!njs_is_data(njs_object_value(&args[0])))) {
-        njs_type_error(vm, "value of \"this\" is not a data type");
+    if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HMAC))) {
+        njs_type_error(vm, "\"this\" is not a hash object");
         return NJS_ERROR;
     }
 
@@ -548,7 +540,7 @@
         }
     }
 
-    ctx = njs_value_data(njs_object_value(&args[0]));
+    ctx = njs_object_data(this);
 
     if (njs_slow_path(ctx->alg == NULL)) {
         njs_error(vm, "Digest already called");
diff --git a/src/njs_extern.c b/src/njs_extern.c
index 3df7604..04bd587 100644
--- a/src/njs_extern.c
+++ b/src/njs_extern.c
@@ -202,7 +202,7 @@
         ov->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
         ov->object.slots = slots;
 
-        njs_set_data(&ov->value, external);
+        njs_set_data(&ov->value, external, NJS_DATA_TAG_EXTERNAL);
         njs_set_object_value(retval, ov);
     }
 
@@ -313,7 +313,7 @@
     ov->object.slots = slots;
 
     njs_set_object_value(value, ov);
-    njs_set_data(&ov->value, external);
+    njs_set_data(&ov->value, external, NJS_DATA_TAG_EXTERNAL);
 
     return NJS_OK;
 }
@@ -322,11 +322,8 @@
 njs_external_ptr_t
 njs_vm_external(njs_vm_t *vm, const njs_value_t *value)
 {
-    if (njs_fast_path(njs_is_object_value(value))) {
-        value = njs_object_value(value);
-        if (njs_fast_path(njs_is_data(value))) {
-            return njs_value_data(value);
-        }
+    if (njs_fast_path(njs_is_object_data(value, NJS_DATA_TAG_EXTERNAL))) {
+        return njs_object_data(value);
     }
 
     return NULL;
diff --git a/src/njs_promise.c b/src/njs_promise.c
index c1db7bc..41704c0 100644
--- a/src/njs_promise.c
+++ b/src/njs_promise.c
@@ -101,7 +101,7 @@
     njs_queue_init(&data->reject_queue);
 
     njs_set_promise(&vm->retval, promise);
-    njs_value_data_set(&promise->value, data);
+    njs_set_data(&promise->value, data, 0);
 
     return promise;
 
@@ -453,7 +453,7 @@
         function = njs_promise_create_function(vm);
         function->u.native = njs_promise_reaction_job;
 
-        njs_set_data(&arguments[0], reaction);
+        njs_set_data(&arguments[0], reaction, 0);
         arguments[1] = *value;
 
         ret = njs_promise_add_event(vm, function, arguments, 2);
@@ -472,7 +472,7 @@
     njs_queue_t         queue;
     njs_promise_data_t  *data;
 
-    data = njs_value_data(&promise->value);
+    data = njs_data(&promise->value);
 
     data->result = *value;
     data->state = NJS_PROMISE_FULFILL;
@@ -500,7 +500,7 @@
     njs_queue_t         queue;
     njs_promise_data_t  *data;
 
-    data = njs_value_data(&promise->value);
+    data = njs_data(&promise->value);
 
     data->result = *reason;
     data->state = NJS_PROMISE_REJECTED;
@@ -845,7 +845,7 @@
     }
 
     promise = njs_promise(value);
-    data = njs_value_data(&promise->value);
+    data = njs_data(&promise->value);
 
     fulfilled_reaction = njs_mp_alloc(vm->mem_pool,
                                       sizeof(njs_promise_reaction_t));
@@ -878,12 +878,12 @@
         function->u.native = njs_promise_reaction_job;
 
         if (data->state == NJS_PROMISE_REJECTED) {
-            njs_set_data(&arguments[0], rejected_reaction);
+            njs_set_data(&arguments[0], rejected_reaction, 0);
 
             /* TODO: HostPromiseRejectionTracker */
 
         } else {
-            njs_set_data(&arguments[0], fulfilled_reaction);
+            njs_set_data(&arguments[0], fulfilled_reaction, 0);
         }
 
         arguments[1] = data->result;
diff --git a/src/njs_value.c b/src/njs_value.c
index a271a77..fc2fbd4 100644
--- a/src/njs_value.c
+++ b/src/njs_value.c
@@ -371,13 +371,6 @@
 }
 
 
-void
-njs_value_data_set(njs_value_t *value, void *data)
-{
-    njs_set_data(value, data);
-}
-
-
 uint8_t
 njs_value_bool(const njs_value_t *value)
 {
@@ -392,13 +385,6 @@
 }
 
 
-void *
-njs_value_data(const njs_value_t *value)
-{
-    return njs_data(value);
-}
-
-
 njs_function_t *
 njs_value_function(const njs_value_t *value)
 {
diff --git a/src/njs_value.h b/src/njs_value.h
index 609eadc..d09b942 100644
--- a/src/njs_value.h
+++ b/src/njs_value.h
@@ -76,6 +76,15 @@
 } njs_value_type_t;
 
 
+typedef enum {
+    NJS_DATA_TAG_ANY = 0,
+    NJS_DATA_TAG_EXTERNAL,
+    NJS_DATA_TAG_CRYPTO_HASH,
+    NJS_DATA_TAG_CRYPTO_HMAC,
+    NJS_DATA_TAG_MAX
+} njs_data_tag_t;
+
+
 typedef struct njs_string_s           njs_string_t;
 typedef struct njs_object_s           njs_object_t;
 typedef struct njs_object_value_s     njs_object_value_t;
@@ -599,8 +608,8 @@
     ((value)->type <= NJS_STRING)
 
 
-#define njs_is_data(value)                                                    \
-    ((value)->type == NJS_DATA)
+#define njs_is_data(value, tag)                                               \
+    ((value)->type == NJS_DATA && value->data.magic32 == (tag))
 
 
 #define njs_is_object(value)                                                  \
@@ -616,6 +625,11 @@
     ((value)->type == NJS_OBJECT_VALUE)
 
 
+#define njs_is_object_data(_value, tag)                                       \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_data(njs_object_value(_value), tag))
+
+
 #define njs_is_object_string(value)                                           \
     ((value)->type == NJS_OBJECT_STRING)
 
@@ -748,6 +762,10 @@
     (&(_value)->data.u.object_value->value)
 
 
+#define njs_object_data(_value)                                               \
+    njs_data(njs_object_value(_value))
+
+
 #define njs_set_undefined(value)                                              \
     *(value) = njs_value_undefined
 
@@ -852,8 +870,9 @@
 
 
 njs_inline void
-njs_set_data(njs_value_t *value, void *data)
+njs_set_data(njs_value_t *value, void *data, njs_data_tag_t tag)
 {
+    value->data.magic32 = tag;
     value->data.u.data = data;
     value->type = NJS_DATA;
     value->data.truth = 1;
diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
index 83cad21..ff87505 100644
--- a/src/test/njs_unit_test.c
+++ b/src/test/njs_unit_test.c
@@ -16956,6 +16956,10 @@
     { njs_str("typeof require('crypto').createHmac('md5', 'a')"),
       njs_str("object") },
 
+    { njs_str("var cr = require('crypto'); var h = cr.createHash('sha1');"
+              "h.update.call(cr.createHmac('sha1', 's'), '')"),
+      njs_str("TypeError: \"this\" is not a hash object") },
+
     /* setTimeout(). */
 
     { njs_str("setTimeout()"),