[njs] Fixed handling of props in Object.getOwnPropertyDescriptor().

Dmitry Volyntsev xeioex at nginx.com
Thu Apr 26 17:36:53 UTC 2018


details:   http://hg.nginx.org/njs/rev/cba7742a0a65
branches:  
changeset: 508:cba7742a0a65
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Apr 26 19:53:16 2018 +0300
description:
Fixed handling of props in Object.getOwnPropertyDescriptor().

njs_property_query() is moved to njs_object.c without changes.

diffstat:

 njs/njs_object.c         |  338 +++++++++++++++++++++++++++++++++++++++++++++-
 njs/njs_object.h         |   16 ++
 njs/njs_vm.c             |  333 ----------------------------------------------
 njs/njs_vm.h             |   18 ++
 njs/test/njs_unit_test.c |    9 +
 5 files changed, 368 insertions(+), 346 deletions(-)

diffs (843 lines):

diff -r ee72fc2329bf -r cba7742a0a65 njs/njs_object.c
--- a/njs/njs_object.c	Thu Apr 26 19:24:55 2018 +0300
+++ b/njs/njs_object.c	Thu Apr 26 19:53:16 2018 +0300
@@ -19,7 +19,9 @@
 #include <njs_string.h>
 #include <njs_object.h>
 #include <njs_object_hash.h>
+#include <njs_number.h>
 #include <njs_array.h>
+#include <njs_extern.h>
 #include <njs_function.h>
 #include <njs_error.h>
 #include <stdio.h>
@@ -27,6 +29,12 @@
 
 
 static nxt_int_t njs_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
+static njs_ret_t njs_object_property_query(njs_vm_t *vm,
+    njs_property_query_t *pq, njs_value_t *value, njs_object_t *object);
+static njs_ret_t njs_array_property_query(njs_vm_t *vm,
+    njs_property_query_t *pq, njs_value_t *object, uint32_t index);
+static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq,
+    njs_object_t *object);
 static njs_ret_t njs_define_property(njs_vm_t *vm, njs_object_t *object,
     const njs_value_t *name, const njs_object_t *descriptor);
 
@@ -229,6 +237,301 @@ njs_object_property(njs_vm_t *vm, const 
 }
 
 
+/*
+ * The njs_property_query() returns values
+ *   NXT_OK               property has been found in object,
+ *   NXT_DECLINED         property was not found in object,
+ *   NJS_PRIMITIVE_VALUE  property operation was applied to a numeric
+ *                        or boolean value,
+ *   NJS_STRING_VALUE     property operation was applied to a string,
+ *   NJS_ARRAY_VALUE      object is array,
+ *   NJS_EXTERNAL_VALUE   object is external entity,
+ *   NJS_TRAP_PROPERTY    the property trap must be called,
+ *   NXT_ERROR            exception has been thrown.
+ */
+
+njs_ret_t
+njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
+    njs_value_t *property)
+{
+    uint32_t            index;
+    uint32_t            (*hash)(const void *, size_t);
+    njs_ret_t           ret;
+    njs_object_t        *obj;
+    njs_function_t      *function;
+    const njs_extern_t  *ext_proto;
+
+    hash = nxt_djb_hash;
+
+    switch (object->type) {
+
+    case NJS_BOOLEAN:
+    case NJS_NUMBER:
+        if (pq->query != NJS_PROPERTY_QUERY_GET) {
+            return NJS_PRIMITIVE_VALUE;
+        }
+
+        index = njs_primitive_prototype_index(object->type);
+        obj = &vm->prototypes[index].object;
+        break;
+
+    case NJS_STRING:
+        if (pq->query == NJS_PROPERTY_QUERY_DELETE) {
+            return NXT_DECLINED;
+        }
+
+        obj = &vm->prototypes[NJS_PROTOTYPE_STRING].object;
+        break;
+
+    case NJS_ARRAY:
+        if (nxt_fast_path(!njs_is_null_or_void_or_boolean(property))) {
+
+            if (nxt_fast_path(njs_is_primitive(property))) {
+                index = njs_value_to_index(property);
+
+                if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) {
+                    return njs_array_property_query(vm, pq, object, index);
+                }
+
+            } else {
+                return NJS_TRAP_PROPERTY;
+            }
+        }
+
+        /* Fall through. */
+
+    case NJS_OBJECT:
+    case NJS_OBJECT_BOOLEAN:
+    case NJS_OBJECT_NUMBER:
+    case NJS_OBJECT_STRING:
+    case NJS_REGEXP:
+    case NJS_DATE:
+    case NJS_OBJECT_ERROR:
+    case NJS_OBJECT_EVAL_ERROR:
+    case NJS_OBJECT_INTERNAL_ERROR:
+    case NJS_OBJECT_RANGE_ERROR:
+    case NJS_OBJECT_REF_ERROR:
+    case NJS_OBJECT_SYNTAX_ERROR:
+    case NJS_OBJECT_TYPE_ERROR:
+    case NJS_OBJECT_URI_ERROR:
+    case NJS_OBJECT_VALUE:
+        obj = object->data.u.object;
+        break;
+
+    case NJS_FUNCTION:
+        function = njs_function_value_copy(vm, object);
+        if (nxt_slow_path(function == NULL)) {
+            return NXT_ERROR;
+        }
+
+        obj = &function->object;
+        break;
+
+    case NJS_EXTERNAL:
+        ext_proto = object->external.proto;
+
+        if (ext_proto->type == NJS_EXTERN_CASELESS_OBJECT) {
+            hash = nxt_djb_hash_lowcase;
+        }
+
+        obj = NULL;
+        break;
+
+    case NJS_VOID:
+    case NJS_NULL:
+    default:
+        if (nxt_fast_path(njs_is_primitive(property))) {
+
+            ret = njs_primitive_value_to_string(vm, &pq->value, property);
+
+            if (nxt_fast_path(ret == NXT_OK)) {
+                njs_string_get(&pq->value, &pq->lhq.key);
+                njs_type_error(vm, "cannot get property '%.*s' of undefined",
+                               (int) pq->lhq.key.length, pq->lhq.key.start);
+                return NXT_ERROR;
+            }
+        }
+
+        njs_type_error(vm, "cannot get property 'unknown' of undefined", NULL);
+
+        return NXT_ERROR;
+    }
+
+    if (nxt_fast_path(njs_is_primitive(property))) {
+
+        ret = njs_primitive_value_to_string(vm, &pq->value, property);
+
+        if (nxt_fast_path(ret == NXT_OK)) {
+
+            njs_string_get(&pq->value, &pq->lhq.key);
+            pq->lhq.key_hash = hash(pq->lhq.key.start, pq->lhq.key.length);
+
+            if (obj == NULL) {
+                pq->lhq.proto = &njs_extern_hash_proto;
+
+                return NJS_EXTERNAL_VALUE;
+            }
+
+            return njs_object_property_query(vm, pq, object, obj);
+        }
+
+        return ret;
+    }
+
+    return NJS_TRAP_PROPERTY;
+}
+
+
+njs_ret_t
+njs_object_property_query(njs_vm_t *vm, njs_property_query_t *pq,
+    njs_value_t *value, njs_object_t *object)
+{
+    njs_ret_t          ret;
+    njs_object_prop_t  *prop;
+
+    pq->lhq.proto = &njs_object_hash_proto;
+
+    if (pq->query == NJS_PROPERTY_QUERY_SET) {
+        ret = njs_object_query_prop_handler(pq, object);
+        if (ret == NXT_OK) {
+            return ret;
+        }
+    }
+
+    do {
+        pq->prototype = object;
+
+        ret = nxt_lvlhsh_find(&object->hash, &pq->lhq);
+
+        if (ret == NXT_OK) {
+            prop = pq->lhq.value;
+
+            if (prop->type != NJS_WHITEOUT) {
+                pq->shared = 0;
+
+                return ret;
+            }
+
+            goto next;
+        }
+
+        if (pq->query > NJS_PROPERTY_QUERY_IN) {
+            /* NXT_DECLINED */
+            return ret;
+        }
+
+        ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
+
+        if (ret == NXT_OK) {
+            pq->shared = 1;
+
+            if (pq->query == NJS_PROPERTY_QUERY_GET) {
+                prop = pq->lhq.value;
+
+                if (prop->type == NJS_PROPERTY_HANDLER) {
+                    pq->scratch = *prop;
+                    prop = &pq->scratch;
+                    ret = prop->value.data.u.prop_handler(vm, value, NULL,
+                                                          &prop->value);
+
+                    if (nxt_fast_path(ret == NXT_OK)) {
+                        prop->type = NJS_PROPERTY;
+                        pq->lhq.value = prop;
+                    }
+                }
+            }
+
+            return ret;
+        }
+
+        if (pq->query > NJS_PROPERTY_QUERY_IN) {
+            /* NXT_DECLINED */
+            return ret;
+        }
+
+    next:
+
+        object = object->__proto__;
+
+    } while (object != NULL);
+
+    if (njs_is_string(value)) {
+        return NJS_STRING_VALUE;
+    }
+
+    /* NXT_DECLINED */
+
+    return ret;
+}
+
+
+static njs_ret_t
+njs_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
+    njs_value_t *object, uint32_t index)
+{
+    uint32_t     size;
+    njs_ret_t    ret;
+    njs_value_t  *value;
+    njs_array_t  *array;
+
+    array = object->data.u.array;
+
+    if (index >= array->length) {
+        if (pq->query != NJS_PROPERTY_QUERY_SET) {
+            return NXT_DECLINED;
+        }
+
+        size = index - array->length;
+
+        ret = njs_array_expand(vm, array, 0, size + 1);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+
+        value = &array->start[array->length];
+
+        while (size != 0) {
+            njs_set_invalid(value);
+            value++;
+            size--;
+        }
+
+        array->length = index + 1;
+    }
+
+    pq->lhq.value = &array->start[index];
+
+    return NJS_ARRAY_VALUE;
+}
+
+
+static njs_ret_t
+njs_object_query_prop_handler(njs_property_query_t *pq, njs_object_t *object)
+{
+    njs_ret_t          ret;
+    njs_object_prop_t  *prop;
+
+    do {
+        pq->prototype = object;
+
+        ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
+
+        if (ret == NXT_OK) {
+            prop = pq->lhq.value;
+
+            if (prop->type == NJS_PROPERTY_HANDLER) {
+                return NXT_OK;
+            }
+        }
+
+        object = object->__proto__;
+
+    } while (object != NULL);
+
+    return NXT_DECLINED;
+}
+
+
 njs_ret_t
 njs_object_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
@@ -618,13 +921,15 @@ static njs_ret_t
 njs_object_get_own_property_descriptor(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused)
 {
-    uint32_t            index;
-    nxt_int_t           ret;
-    njs_array_t         *array;
-    njs_object_t        *descriptor;
-    njs_object_prop_t   *pr, *prop, array_prop;
-    const njs_value_t   *value, *property, *setval;
-    nxt_lvlhsh_query_t  lhq;
+    double                num;
+    uint32_t              index;
+    nxt_int_t             ret;
+    njs_array_t           *array;
+    njs_object_t          *descriptor;
+    njs_object_prop_t     *pr, *prop, array_prop;
+    const njs_value_t     *value, *property, *setval;
+    nxt_lvlhsh_query_t    lhq;
+    njs_property_query_t  pq;
 
     value = njs_arg(args, nargs, 1);
 
@@ -644,9 +949,13 @@ njs_object_get_own_property_descriptor(n
 
     if (njs_is_array(value)) {
         array = value->data.u.array;
-        index = njs_string_to_index(property);
+        num = njs_string_to_index(property);
+        index = num;
 
-        if (index < array->length && njs_is_valid(&array->start[index])) {
+        if ((double) index == num
+            && index < array->length
+            && njs_is_valid(&array->start[index]))
+        {
             prop = &array_prop;
 
             array_prop.name = *property;
@@ -661,17 +970,19 @@ njs_object_get_own_property_descriptor(n
     lhq.proto = &njs_object_hash_proto;
 
     if (prop == NULL) {
-        njs_string_get(property, &lhq.key);
-        lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+        pq.query = NJS_PROPERTY_QUERY_GET;
+        pq.lhq.key.length = 0;
+        pq.lhq.key.start = NULL;
 
-        ret = nxt_lvlhsh_find(&value->data.u.object->hash, &lhq);
+        ret = njs_property_query(vm, &pq, (njs_value_t *) value,
+                                 (njs_value_t *) property);
 
         if (ret != NXT_OK) {
             vm->retval = njs_value_void;
             return NXT_OK;
         }
 
-        prop = lhq.value;
+        prop = pq.lhq.value;
     }
 
     descriptor = njs_object_alloc(vm);
@@ -681,6 +992,7 @@ njs_object_get_own_property_descriptor(n
 
     lhq.replace = 0;
     lhq.pool = vm->mem_cache_pool;
+    lhq.proto = &njs_object_hash_proto;
 
     lhq.key = nxt_string_value("value");
     lhq.key_hash = NJS_VALUE_HASH;
diff -r ee72fc2329bf -r cba7742a0a65 njs/njs_object.h
--- a/njs/njs_object.h	Thu Apr 26 19:24:55 2018 +0300
+++ b/njs/njs_object.h	Thu Apr 26 19:53:16 2018 +0300
@@ -30,6 +30,20 @@ typedef struct {
 } njs_object_prop_t;
 
 
+typedef struct {
+    nxt_lvlhsh_query_t          lhq;
+
+    /* scratch is used to get the value of an NJS_PROPERTY_HANDLER property. */
+    njs_object_prop_t           scratch;
+
+    njs_value_t                 value;
+    njs_object_t                *prototype;
+    uint8_t                     query;
+    uint8_t                     shared;
+} njs_property_query_t;
+
+
+
 struct njs_object_init_s {
     nxt_str_t                   name;
     const njs_object_prop_t     *properties;
@@ -44,6 +58,8 @@ njs_object_t *njs_object_value_alloc(njs
 njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object);
 njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj,
     nxt_lvlhsh_query_t *lhq);
+njs_ret_t njs_property_query(njs_vm_t *vm, njs_property_query_t *pq,
+    njs_value_t *object, njs_value_t *property);
 nxt_int_t njs_object_hash_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
     const njs_object_prop_t *prop, nxt_uint_t n);
 njs_ret_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args,
diff -r ee72fc2329bf -r cba7742a0a65 njs/njs_vm.c
--- a/njs/njs_vm.c	Thu Apr 26 19:24:55 2018 +0300
+++ b/njs/njs_vm.c	Thu Apr 26 19:53:16 2018 +0300
@@ -33,36 +33,6 @@
 #include <stdio.h>
 
 
-/* The values must be greater than NXT_OK. */
-#define NJS_PRIMITIVE_VALUE        1
-#define NJS_STRING_VALUE           2
-#define NJS_ARRAY_VALUE            3
-#define NJS_EXTERNAL_VALUE         4
-
-
-/*
- * NJS_PROPERTY_QUERY_GET must be less or equal to NJS_PROPERTY_QUERY_IN,
- * NJS_PROPERTY_QUERY_SET and NJS_PROPERTY_QUERY_DELETE must be greater
- * than NJS_PROPERTY_QUERY_IN.
- */
-#define NJS_PROPERTY_QUERY_GET     0
-#define NJS_PROPERTY_QUERY_IN      1
-#define NJS_PROPERTY_QUERY_SET     2
-#define NJS_PROPERTY_QUERY_DELETE  3
-
-
-typedef struct {
-    nxt_lvlhsh_query_t             lhq;
-
-    /* scratch is used to get the value of an NJS_PROPERTY_HANDLER property. */
-    njs_object_prop_t              scratch;
-
-    njs_value_t                    value;
-    njs_object_t                   *prototype;
-    uint8_t                        query;
-    uint8_t                        shared;
-} njs_property_query_t;
-
 
 struct njs_property_next_s {
     int32_t                        index;
@@ -76,14 +46,6 @@ struct njs_property_next_s {
  * and should fit in CPU L1 instruction cache.
  */
 
-static nxt_noinline njs_ret_t njs_property_query(njs_vm_t *vm,
-    njs_property_query_t *pq, njs_value_t *object, njs_value_t *property);
-static njs_ret_t njs_array_property_query(njs_vm_t *vm,
-    njs_property_query_t *pq, njs_value_t *object, uint32_t index);
-static njs_ret_t njs_object_property_query(njs_vm_t *vm,
-    njs_property_query_t *pq, njs_value_t *value, njs_object_t *object);
-static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq,
-    njs_object_t *object);
 static njs_ret_t njs_method_private_copy(njs_vm_t *vm,
     njs_property_query_t *pq);
 static nxt_noinline njs_ret_t njs_values_equal(const njs_value_t *val1,
@@ -972,301 +934,6 @@ njs_vmcode_property_delete(njs_vm_t *vm,
 }
 
 
-/*
- * The njs_property_query() returns values
- *   NXT_OK               property has been found in object,
- *   NXT_DECLINED         property was not found in object,
- *   NJS_PRIMITIVE_VALUE  property operation was applied to a numeric
- *                        or boolean value,
- *   NJS_STRING_VALUE     property operation was applied to a string,
- *   NJS_ARRAY_VALUE      object is array,
- *   NJS_EXTERNAL_VALUE   object is external entity,
- *   NJS_TRAP_PROPERTY    the property trap must be called,
- *   NXT_ERROR            exception has been thrown.
- */
-
-static nxt_noinline njs_ret_t
-njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
-    njs_value_t *property)
-{
-    uint32_t            index;
-    uint32_t            (*hash)(const void *, size_t);
-    njs_ret_t           ret;
-    njs_object_t        *obj;
-    njs_function_t      *function;
-    const njs_extern_t  *ext_proto;
-
-    hash = nxt_djb_hash;
-
-    switch (object->type) {
-
-    case NJS_BOOLEAN:
-    case NJS_NUMBER:
-        if (pq->query != NJS_PROPERTY_QUERY_GET) {
-            return NJS_PRIMITIVE_VALUE;
-        }
-
-        index = njs_primitive_prototype_index(object->type);
-        obj = &vm->prototypes[index].object;
-        break;
-
-    case NJS_STRING:
-        if (pq->query == NJS_PROPERTY_QUERY_DELETE) {
-            return NXT_DECLINED;
-        }
-
-        obj = &vm->prototypes[NJS_PROTOTYPE_STRING].object;
-        break;
-
-    case NJS_ARRAY:
-        if (nxt_fast_path(!njs_is_null_or_void_or_boolean(property))) {
-
-            if (nxt_fast_path(njs_is_primitive(property))) {
-                index = njs_value_to_index(property);
-
-                if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) {
-                    return njs_array_property_query(vm, pq, object, index);
-                }
-
-            } else {
-                return NJS_TRAP_PROPERTY;
-            }
-        }
-
-        /* Fall through. */
-
-    case NJS_OBJECT:
-    case NJS_OBJECT_BOOLEAN:
-    case NJS_OBJECT_NUMBER:
-    case NJS_OBJECT_STRING:
-    case NJS_REGEXP:
-    case NJS_DATE:
-    case NJS_OBJECT_ERROR:
-    case NJS_OBJECT_EVAL_ERROR:
-    case NJS_OBJECT_INTERNAL_ERROR:
-    case NJS_OBJECT_RANGE_ERROR:
-    case NJS_OBJECT_REF_ERROR:
-    case NJS_OBJECT_SYNTAX_ERROR:
-    case NJS_OBJECT_TYPE_ERROR:
-    case NJS_OBJECT_URI_ERROR:
-    case NJS_OBJECT_VALUE:
-        obj = object->data.u.object;
-        break;
-
-    case NJS_FUNCTION:
-        function = njs_function_value_copy(vm, object);
-        if (nxt_slow_path(function == NULL)) {
-            return NXT_ERROR;
-        }
-
-        obj = &function->object;
-        break;
-
-    case NJS_EXTERNAL:
-        ext_proto = object->external.proto;
-
-        if (ext_proto->type == NJS_EXTERN_CASELESS_OBJECT) {
-            hash = nxt_djb_hash_lowcase;
-        }
-
-        obj = NULL;
-        break;
-
-    case NJS_VOID:
-    case NJS_NULL:
-    default:
-        if (nxt_fast_path(njs_is_primitive(property))) {
-
-            ret = njs_primitive_value_to_string(vm, &pq->value, property);
-
-            if (nxt_fast_path(ret == NXT_OK)) {
-                njs_string_get(&pq->value, &pq->lhq.key);
-                njs_type_error(vm, "cannot get property '%.*s' of undefined",
-                               (int) pq->lhq.key.length, pq->lhq.key.start);
-                return NXT_ERROR;
-            }
-        }
-
-        njs_type_error(vm, "cannot get property 'unknown' of undefined", NULL);
-
-        return NXT_ERROR;
-    }
-
-    if (nxt_fast_path(njs_is_primitive(property))) {
-
-        ret = njs_primitive_value_to_string(vm, &pq->value, property);
-
-        if (nxt_fast_path(ret == NXT_OK)) {
-
-            njs_string_get(&pq->value, &pq->lhq.key);
-            pq->lhq.key_hash = hash(pq->lhq.key.start, pq->lhq.key.length);
-
-            if (obj == NULL) {
-                pq->lhq.proto = &njs_extern_hash_proto;
-
-                return NJS_EXTERNAL_VALUE;
-            }
-
-            return njs_object_property_query(vm, pq, object, obj);
-        }
-
-        return ret;
-    }
-
-    return NJS_TRAP_PROPERTY;
-}
-
-
-static njs_ret_t
-njs_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
-    njs_value_t *object, uint32_t index)
-{
-    uint32_t     size;
-    njs_ret_t    ret;
-    njs_value_t  *value;
-    njs_array_t  *array;
-
-    array = object->data.u.array;
-
-    if (index >= array->length) {
-        if (pq->query != NJS_PROPERTY_QUERY_SET) {
-            return NXT_DECLINED;
-        }
-
-        size = index - array->length;
-
-        ret = njs_array_expand(vm, array, 0, size + 1);
-        if (nxt_slow_path(ret != NXT_OK)) {
-            return ret;
-        }
-
-        value = &array->start[array->length];
-
-        while (size != 0) {
-            njs_set_invalid(value);
-            value++;
-            size--;
-        }
-
-        array->length = index + 1;
-    }
-
-    pq->lhq.value = &array->start[index];
-
-    return NJS_ARRAY_VALUE;
-}
-
-
-static njs_ret_t
-njs_object_property_query(njs_vm_t *vm, njs_property_query_t *pq,
-    njs_value_t *value, njs_object_t *object)
-{
-    njs_ret_t          ret;
-    njs_object_prop_t  *prop;
-
-    pq->lhq.proto = &njs_object_hash_proto;
-
-    if (pq->query == NJS_PROPERTY_QUERY_SET) {
-        ret = njs_object_query_prop_handler(pq, object);
-        if (ret == NXT_OK) {
-            return ret;
-        }
-    }
-
-    do {
-        pq->prototype = object;
-
-        ret = nxt_lvlhsh_find(&object->hash, &pq->lhq);
-
-        if (ret == NXT_OK) {
-            prop = pq->lhq.value;
-
-            if (prop->type != NJS_WHITEOUT) {
-                pq->shared = 0;
-
-                return ret;
-            }
-
-            goto next;
-        }
-
-        if (pq->query > NJS_PROPERTY_QUERY_IN) {
-            /* NXT_DECLINED */
-            return ret;
-        }
-
-        ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
-
-        if (ret == NXT_OK) {
-            pq->shared = 1;
-
-            if (pq->query == NJS_PROPERTY_QUERY_GET) {
-                prop = pq->lhq.value;
-
-                if (prop->type == NJS_PROPERTY_HANDLER) {
-                    pq->scratch = *prop;
-                    prop = &pq->scratch;
-                    ret = prop->value.data.u.prop_handler(vm, value, NULL,
-                                                          &prop->value);
-
-                    if (nxt_fast_path(ret == NXT_OK)) {
-                        prop->type = NJS_PROPERTY;
-                        pq->lhq.value = prop;
-                    }
-                }
-            }
-
-            return ret;
-        }
-
-        if (pq->query > NJS_PROPERTY_QUERY_IN) {
-            /* NXT_DECLINED */
-            return ret;
-        }
-
-    next:
-
-        object = object->__proto__;
-
-    } while (object != NULL);
-
-    if (njs_is_string(value)) {
-        return NJS_STRING_VALUE;
-    }
-
-    /* NXT_DECLINED */
-
-    return ret;
-}
-
-
-static njs_ret_t
-njs_object_query_prop_handler(njs_property_query_t *pq, njs_object_t *object)
-{
-    njs_ret_t          ret;
-    njs_object_prop_t  *prop;
-
-    do {
-        pq->prototype = object;
-
-        ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
-
-        if (ret == NXT_OK) {
-            prop = pq->lhq.value;
-
-            if (prop->type == NJS_PROPERTY_HANDLER) {
-                return NXT_OK;
-            }
-        }
-
-        object = object->__proto__;
-
-    } while (object != NULL);
-
-    return NXT_DECLINED;
-}
-
-
 static njs_ret_t
 njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
 {
diff -r ee72fc2329bf -r cba7742a0a65 njs/njs_vm.h
--- a/njs/njs_vm.h	Thu Apr 26 19:24:55 2018 +0300
+++ b/njs/njs_vm.h	Thu Apr 26 19:53:16 2018 +0300
@@ -49,6 +49,24 @@
 #define NJS_APPLIED              NXT_DONE
 
 
+/* The values must be greater than NXT_OK. */
+#define NJS_PRIMITIVE_VALUE        1
+#define NJS_STRING_VALUE           2
+#define NJS_ARRAY_VALUE            3
+#define NJS_EXTERNAL_VALUE         4
+
+
+/*
+ * NJS_PROPERTY_QUERY_GET must be less or equal to NJS_PROPERTY_QUERY_IN,
+ * NJS_PROPERTY_QUERY_SET and NJS_PROPERTY_QUERY_DELETE must be greater
+ * than NJS_PROPERTY_QUERY_IN.
+ */
+#define NJS_PROPERTY_QUERY_GET     0
+#define NJS_PROPERTY_QUERY_IN      1
+#define NJS_PROPERTY_QUERY_SET     2
+#define NJS_PROPERTY_QUERY_DELETE  3
+
+
 /*
  * The order of the enum is used in njs_vmcode_typeof()
  * and njs_object_prototype_to_string().
diff -r ee72fc2329bf -r cba7742a0a65 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Apr 26 19:24:55 2018 +0300
+++ b/njs/test/njs_unit_test.c	Thu Apr 26 19:53:16 2018 +0300
@@ -6596,6 +6596,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Object.getOwnPropertyDescriptor([3,4], 1).value"),
       nxt_string("4") },
 
+    { nxt_string("Object.getOwnPropertyDescriptor([], 'length').value"),
+      nxt_string("0") },
+
     { nxt_string("Object.getOwnPropertyDescriptor([3,4], '3')"),
       nxt_string("undefined") },
 
@@ -6611,6 +6614,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Object.getOwnPropertyDescriptor(undefined)"),
       nxt_string("TypeError: cannot convert void argument to object") },
 
+    { nxt_string("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o).value"),
+      nxt_string("a") },
+
+    { nxt_string("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o, undefined).value"),
+      nxt_string("a") },
+
     { nxt_string("Object.defineProperty(Object.freeze({}), 'b', {})"),
       nxt_string("TypeError: object is not extensible") },
 


More information about the nginx-devel mailing list