[njs] Fixed objects instance properties.

Dmitry Volyntsev xeioex at nginx.com
Fri Apr 12 15:36:12 UTC 2019


details:   https://hg.nginx.org/njs/rev/1213e0a2b485
branches:  
changeset: 885:1213e0a2b485
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Apr 12 18:36:02 2019 +0300
description:
Fixed objects instance properties.

Some properties like 'length' of Array, String or Function
objects should be instance properties not prototype properties.

diffstat:

 njs/njs_array.c          |   26 +++++++-
 njs/njs_array.h          |    1 +
 njs/njs_builtin.c        |   92 ++++++++++++++++--------------
 njs/njs_extern.c         |    2 +-
 njs/njs_function.c       |   58 +++++++++++++++++--
 njs/njs_function.h       |    4 +-
 njs/njs_number.c         |   88 ++++++++++++++++++++++++++--
 njs/njs_object.c         |   40 +++++--------
 njs/njs_string.c         |  141 +++++++++++++++++++++++++++++++++++++++++-----
 njs/njs_string.h         |    1 +
 njs/njs_vm.h             |    9 ++-
 njs/test/njs_unit_test.c |   60 +++++++++++++++++++-
 12 files changed, 411 insertions(+), 111 deletions(-)

diffs (truncated from 1033 to 1000 lines):

diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_array.c
--- a/njs/njs_array.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_array.c	Fri Apr 12 18:36:02 2019 +0300
@@ -149,7 +149,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l
 
     array->start = array->data;
     nxt_lvlhsh_init(&array->object.hash);
-    nxt_lvlhsh_init(&array->object.shared_hash);
+    array->object.shared_hash = vm->shared->array_instance_hash;
     array->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_ARRAY].object;
     array->object.type = NJS_ARRAY;
     array->object.shared = 0;
@@ -401,8 +401,8 @@ const njs_object_init_t  njs_array_const
 
 
 static njs_ret_t
-njs_array_prototype_length(njs_vm_t *vm, njs_value_t *value,
-    njs_value_t *setval, njs_value_t *retval)
+njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval,
+    njs_value_t *retval)
 {
     double       num;
     int64_t      size;
@@ -2214,7 +2214,7 @@ static const njs_object_prop_t  njs_arra
     {
         .type = NJS_PROPERTY_HANDLER,
         .name = njs_string("length"),
-        .value = njs_prop_handler(njs_array_prototype_length),
+        .value = njs_prop_handler(njs_array_length),
         .writable = 1
     },
 
@@ -2395,3 +2395,21 @@ const njs_object_init_t  njs_array_proto
     njs_array_prototype_properties,
     nxt_nitems(njs_array_prototype_properties),
 };
+
+
+const njs_object_prop_t  njs_array_instance_properties[] =
+{
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("length"),
+        .value = njs_prop_handler(njs_array_length),
+        .writable = 1
+    },
+};
+
+
+const njs_object_init_t  njs_array_instance_init = {
+    nxt_string("Array instance"),
+    njs_array_instance_properties,
+    nxt_nitems(njs_array_instance_properties),
+};
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_array.h
--- a/njs/njs_array.h	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_array.h	Fri Apr 12 18:36:02 2019 +0300
@@ -26,6 +26,7 @@ njs_ret_t njs_array_constructor(njs_vm_t
 
 extern const njs_object_init_t  njs_array_constructor_init;
 extern const njs_object_init_t  njs_array_prototype_init;
+extern const njs_object_init_t  njs_array_instance_init;
 
 
 #endif /* _NJS_ARRAY_H_INCLUDED_ */
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_builtin.c
--- a/njs/njs_builtin.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_builtin.c	Fri Apr 12 18:36:02 2019 +0300
@@ -138,22 +138,6 @@ const njs_function_init_t  njs_native_fu
 };
 
 
-const njs_object_prop_t  njs_arguments_object_properties[] =
-{
-    {
-        .type = NJS_PROPERTY_HANDLER,
-        .name = njs_string("caller"),
-        .value = njs_prop_handler(njs_function_arguments_thrower),
-    },
-
-    {
-        .type = NJS_PROPERTY_HANDLER,
-        .name = njs_string("callee"),
-        .value = njs_prop_handler(njs_function_arguments_thrower),
-    },
-};
-
-
 const njs_function_init_t  njs_native_constructors[] = {
     /* SunC does not allow empty array initialization. */
     { njs_object_constructor,     { 0 } },
@@ -230,48 +214,61 @@ const njs_object_prototype_t  njs_protot
 };
 
 
+nxt_inline nxt_int_t
+njs_object_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash,
+    const njs_object_init_t *init)
+{
+    return njs_object_hash_create(vm, hash, init->properties, init->items);
+}
+
 
 nxt_int_t
 njs_builtin_objects_create(njs_vm_t *vm)
 {
     nxt_int_t                  ret;
     njs_module_t               *module;
-    njs_object_t               *object;
+    njs_object_t               *object, *string_object;
     njs_function_t             *func;
     nxt_lvlhsh_query_t         lhq;
+    njs_vm_shared_t            *shared;
     njs_object_prototype_t     *prototype;
     const njs_object_init_t    *obj, **p;
     const njs_function_init_t  *f;
 
-    static const njs_object_prop_t    function_prototype_property = {
-        .type = NJS_PROPERTY_HANDLER,
-        .name = njs_string("prototype"),
-        .value = njs_prop_handler(njs_function_prototype_create),
-    };
-
     static const nxt_str_t  sandbox_key = nxt_string("sandbox");
 
-    ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash,
-                                 &function_prototype_property, 1);
+    shared = vm->shared;
+
+    ret = njs_object_hash_init(vm, &shared->array_instance_hash,
+                               &njs_array_instance_init);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NXT_ERROR;
+    }
+
+    ret = njs_object_hash_init(vm, &shared->string_instance_hash,
+                               &njs_string_instance_init);
     if (nxt_slow_path(ret != NXT_OK)) {
         return NXT_ERROR;
     }
 
-    ret = njs_object_hash_create(vm, &vm->shared->arguments_object_hash,
-                                 njs_arguments_object_properties,
-                                 nxt_nitems(njs_arguments_object_properties));
+    ret = njs_object_hash_init(vm, &shared->function_instance_hash,
+                               &njs_function_instance_init);
     if (nxt_slow_path(ret != NXT_OK)) {
         return NXT_ERROR;
     }
 
-    object = vm->shared->objects;
+    ret = njs_object_hash_init(vm, &shared->arguments_object_instance_hash,
+                               &njs_arguments_object_instance_init);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NXT_ERROR;
+    }
+
+    object = shared->objects;
 
     for (p = njs_object_init; *p != NULL; p++) {
         obj = *p;
 
-        ret = njs_object_hash_create(vm, &object->shared_hash,
-                                     obj->properties, obj->items);
-
+        ret = njs_object_hash_init(vm, &object->shared_hash, obj);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -295,8 +292,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
 
         module->function.native = 1;
 
-        ret = njs_object_hash_create(vm, &module->object.shared_hash,
-                                     obj->properties, obj->items);
+        ret = njs_object_hash_init(vm, &module->object.shared_hash, obj);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -327,13 +323,12 @@ njs_builtin_objects_create(njs_vm_t *vm)
     }
 
     f = njs_native_functions;
-    func = vm->shared->functions;
+    func = shared->functions;
 
     for (p = njs_function_init; *p != NULL; p++) {
         obj = *p;
 
-        ret = njs_object_hash_create(vm, &func->object.shared_hash,
-                                     obj->properties, obj->items);
+        ret = njs_object_hash_init(vm, &func->object.shared_hash, obj);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -350,14 +345,13 @@ njs_builtin_objects_create(njs_vm_t *vm)
         func++;
     }
 
-    prototype = vm->shared->prototypes;
+    prototype = shared->prototypes;
     memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values));
 
     for (p = njs_prototype_init; *p != NULL; p++) {
         obj = *p;
 
-        ret = njs_object_hash_create(vm, &prototype->object.shared_hash,
-                                     obj->properties, obj->items);
+        ret = njs_object_hash_init(vm, &prototype->object.shared_hash, obj);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -367,11 +361,19 @@ njs_builtin_objects_create(njs_vm_t *vm)
         prototype++;
     }
 
-    vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern =
+    shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern =
                                               vm->shared->empty_regexp_pattern;
 
+    string_object = &shared->string_object;
+    nxt_lvlhsh_init(&string_object->hash);
+    string_object->shared_hash = vm->shared->string_instance_hash;
+    string_object->type = NJS_OBJECT_STRING;
+    string_object->shared = 1;
+    string_object->extensible = 0;
+    string_object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object;
+
     f = njs_native_constructors;
-    func = vm->shared->constructors;
+    func = shared->constructors;
 
     for (p = njs_constructor_init; *p != NULL; p++) {
         obj = *p;
@@ -386,8 +388,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
 
         memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX);
 
-        ret = njs_object_hash_create(vm, &func->object.shared_hash,
-                                     obj->properties, obj->items);
+        ret = njs_object_hash_init(vm, &func->object.shared_hash, obj);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -523,6 +524,9 @@ njs_builtin_objects_clone(njs_vm_t *vm)
         vm->constructors[i].object.__proto__ = function_prototype;
     }
 
+    vm->string_object = vm->shared->string_object;
+    vm->string_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object;
+
     return NXT_OK;
 }
 
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_extern.c
--- a/njs/njs_extern.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_extern.c	Fri Apr 12 18:36:02 2019 +0300
@@ -109,7 +109,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv
 
             function->object.__proto__ =
                               &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object;
-            function->object.shared_hash = vm->shared->function_prototype_hash;
+            function->object.shared_hash = vm->shared->function_instance_hash;
             function->object.type = NJS_FUNCTION;
             function->object.shared = 1;
             function->object.extensible = 1;
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_function.c
--- a/njs/njs_function.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_function.c	Fri Apr 12 18:36:02 2019 +0300
@@ -42,7 +42,7 @@ njs_function_alloc(njs_vm_t *vm, njs_fun
     function->args_offset = 1;
     function->u.lambda = lambda;
 
-    function->object.shared_hash = vm->shared->function_prototype_hash;
+    function->object.shared_hash = vm->shared->function_instance_hash;
     function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object;
     function->object.type = NJS_FUNCTION;
     function->object.shared = shared;
@@ -162,7 +162,7 @@ njs_function_arguments_object_init(njs_v
         return NXT_ERROR;
     }
 
-    arguments->shared_hash = vm->shared->arguments_object_hash;
+    arguments->shared_hash = vm->shared->arguments_object_instance_hash;
 
     nargs = frame->nargs;
 
@@ -250,7 +250,7 @@ njs_function_rest_parameters_init(njs_vm
 }
 
 
-njs_ret_t
+static njs_ret_t
 njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value,
     njs_value_t *setval, njs_value_t *retval)
 {
@@ -259,6 +259,29 @@ njs_function_arguments_thrower(njs_vm_t 
 }
 
 
+const njs_object_prop_t  njs_arguments_object_instance_properties[] =
+{
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("caller"),
+        .value = njs_prop_handler(njs_function_arguments_thrower),
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("callee"),
+        .value = njs_prop_handler(njs_function_arguments_thrower),
+    },
+};
+
+
+const njs_object_init_t  njs_arguments_object_instance_init = {
+    nxt_string("Argument object instance"),
+    njs_arguments_object_instance_properties,
+    nxt_nitems(njs_arguments_object_instance_properties),
+};
+
+
 njs_ret_t
 njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
     const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs,
@@ -861,7 +884,7 @@ const njs_object_init_t  njs_function_co
  *      the typical number of arguments expected by the function.
  */
 static njs_ret_t
-njs_function_prototype_length(njs_vm_t *vm, njs_value_t *value,
+njs_function_instance_length(njs_vm_t *vm, njs_value_t *value,
     njs_value_t *setval, njs_value_t *retval)
 {
     nxt_uint_t             n;
@@ -1117,9 +1140,9 @@ njs_function_prototype_bind(njs_vm_t *vm
 static const njs_object_prop_t  njs_function_prototype_properties[] =
 {
     {
-        .type = NJS_PROPERTY_HANDLER,
+        .type = NJS_PROPERTY,
         .name = njs_string("length"),
-        .value = njs_prop_handler(njs_function_prototype_length),
+        .value = njs_value(NJS_NUMBER, 0, 0.0),
     },
 
     {
@@ -1149,6 +1172,29 @@ const njs_object_init_t  njs_function_pr
 };
 
 
+const njs_object_prop_t  njs_function_instance_properties[] =
+{
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("length"),
+        .value = njs_prop_handler(njs_function_instance_length),
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_function_prototype_create),
+    },
+};
+
+
+const njs_object_init_t  njs_function_instance_init = {
+    nxt_string("Function instance"),
+    njs_function_instance_properties,
+    nxt_nitems(njs_function_instance_properties),
+};
+
+
 njs_ret_t
 njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_function.h
--- a/njs/njs_function.h	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_function.h	Fri Apr 12 18:36:02 2019 +0300
@@ -153,8 +153,6 @@ njs_ret_t njs_function_arguments_object_
     njs_native_frame_t *frame);
 njs_ret_t njs_function_rest_parameters_init(njs_vm_t *vm,
     njs_native_frame_t *frame);
-njs_ret_t njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value,
-    njs_value_t *setval, njs_value_t *retval);
 njs_ret_t njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value,
     njs_value_t *setval, njs_value_t *retval);
 njs_value_t *njs_function_property_prototype_create(njs_vm_t *vm,
@@ -219,6 +217,8 @@ njs_function_previous_frame(njs_native_f
 
 extern const njs_object_init_t  njs_function_constructor_init;
 extern const njs_object_init_t  njs_function_prototype_init;
+extern const njs_object_init_t  njs_function_instance_init;
+extern const njs_object_init_t  njs_arguments_object_instance_init;
 
 njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused);
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_number.c
--- a/njs/njs_number.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_number.c	Fri Apr 12 18:36:02 2019 +0300
@@ -820,29 +820,101 @@ njs_number_to_integer(double num)
 }
 
 
+static const njs_object_prop_t  njs_is_nan_function_properties[] =
+{
+    /* isNaN.name == "isNaN". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("isNaN"),
+    },
+
+    /* isNaN.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
+};
+
+
 const njs_object_init_t  njs_is_nan_function_init = {
     nxt_string("isNaN"),
-    NULL,
-    0,
+    njs_is_nan_function_properties,
+    nxt_nitems(njs_is_nan_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_is_finite_function_properties[] =
+{
+    /* isFinite.name == "isFinite". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("isFinite"),
+    },
+
+    /* isFinite.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_is_finite_function_init = {
     nxt_string("isFinite"),
-    NULL,
-    0,
+    njs_is_finite_function_properties,
+    nxt_nitems(njs_is_finite_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_parse_int_function_properties[] =
+{
+    /* parseInt.name == "parseInt". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("parseInt"),
+    },
+
+    /* parseInt.length == 2. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 2.0),
+    },
 };
 
 
 const njs_object_init_t  njs_parse_int_function_init = {
     nxt_string("parseInt"),
-    NULL,
-    0,
+    njs_parse_int_function_properties,
+    nxt_nitems(njs_parse_int_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_parse_float_function_properties[] =
+{
+    /* parseFloat.name == "parseFloat". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("parseFloat"),
+    },
+
+    /* parseFloat.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_parse_float_function_init = {
     nxt_string("parseFloat"),
-    NULL,
-    0,
+    njs_parse_float_function_properties,
+    nxt_nitems(njs_parse_float_function_properties),
 };
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_object.c
--- a/njs/njs_object.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_object.c	Fri Apr 12 18:36:02 2019 +0300
@@ -294,7 +294,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
             }
         }
 
-        obj = &vm->prototypes[NJS_PROTOTYPE_STRING].object;
+        obj = &vm->string_object;
         break;
 
     case NJS_OBJECT_STRING:
@@ -764,6 +764,8 @@ njs_method_private_copy(njs_vm_t *vm, nj
         return NXT_ERROR;
     }
 
+    function->object.shared_hash = vm->shared->function_instance_hash;
+
     pq->lhq.replace = 0;
     pq->lhq.value = prop;
     pq->lhq.pool = vm->mem_pool;
@@ -954,25 +956,20 @@ njs_array_t *
 njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind, nxt_bool_t all)
 {
-    nxt_bool_t         exotic_length;
     u_char             *dst;
     uint32_t           i, length, size, items_length, properties;
     njs_value_t        *string, *item;
     njs_array_t        *items, *array, *entry;
     nxt_lvlhsh_t       *hash;
     const u_char       *src, *end;
+    njs_object_t       *object;
     njs_object_prop_t  *prop;
     njs_string_prop_t  string_prop;
     nxt_lvlhsh_each_t  lhe;
 
-    static const njs_value_t  njs_string_length = njs_string("length");
-
-    /* TODO: "length" is in a shared_hash. */
-
-    exotic_length = 0;
-
     array = NULL;
     length = 0;
+    object = NULL;
     items_length = 0;
 
     switch (value->type) {
@@ -986,8 +983,6 @@ njs_object_enumerate(njs_vm_t *vm, const
             }
         }
 
-        exotic_length = all;
-
         break;
 
     case NJS_STRING:
@@ -997,19 +992,14 @@ njs_object_enumerate(njs_vm_t *vm, const
 
         } else {
             string = (njs_value_t *) value;
+            object = &vm->string_object;
         }
 
         length = njs_string_prop(&string_prop, string);
         items_length += length;
-        exotic_length = all;
 
         break;
 
-    case NJS_FUNCTION:
-        exotic_length = all && (value->data.u.function->native == 0);
-
-        /* Fall through. */
-
     default:
         break;
     }
@@ -1019,8 +1009,12 @@ njs_object_enumerate(njs_vm_t *vm, const
     properties = 0;
 
     if (nxt_fast_path(njs_is_object(value))) {
+        object = value->data.u.object;
+    }
+
+    if (object != NULL) {
         nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
-        hash = &value->data.u.object->hash;
+        hash = &object->hash;
 
         for ( ;; ) {
             prop = nxt_lvlhsh_each(hash, &lhe);
@@ -1036,7 +1030,7 @@ njs_object_enumerate(njs_vm_t *vm, const
 
         if (nxt_slow_path(all)) {
             nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
-            hash = &value->data.u.object->shared_hash;
+            hash = &object->shared_hash;
 
             for ( ;; ) {
                 prop = nxt_lvlhsh_each(hash, &lhe);
@@ -1052,7 +1046,7 @@ njs_object_enumerate(njs_vm_t *vm, const
         items_length += properties;
     }
 
-    items = njs_array_alloc(vm, items_length + exotic_length, NJS_ARRAY_SPARE);
+    items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE);
     if (nxt_slow_path(items == NULL)) {
         return NULL;
     }
@@ -1210,14 +1204,10 @@ njs_object_enumerate(njs_vm_t *vm, const
         }
     }
 
-    if (nxt_slow_path(exotic_length != 0)) {
-        *item++ = njs_string_length;
-    }
-
     if (nxt_fast_path(properties != 0)) {
         nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
 
-        hash = &value->data.u.object->hash;
+        hash = &object->hash;
 
         switch (kind) {
 
@@ -1236,7 +1226,7 @@ njs_object_enumerate(njs_vm_t *vm, const
 
             if (nxt_slow_path(all)) {
                 nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
-                hash = &value->data.u.object->shared_hash;
+                hash = &object->shared_hash;
 
                 for ( ;; ) {
                     prop = nxt_lvlhsh_each(hash, &lhe);
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_string.c
--- a/njs/njs_string.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_string.c	Fri Apr 12 18:36:02 2019 +0300
@@ -555,6 +555,8 @@ njs_string_constructor(njs_vm_t *vm, njs
             return NXT_ERROR;
         }
 
+        object->shared_hash = vm->shared->string_instance_hash;
+
         vm->retval.data.u.object = object;
         vm->retval.type = NJS_OBJECT_STRING;
         vm->retval.data.truth = 1;
@@ -623,7 +625,7 @@ const njs_object_init_t  njs_string_cons
 
 
 static njs_ret_t
-njs_string_prototype_length(njs_vm_t *vm, njs_value_t *value,
+njs_string_instance_length(njs_vm_t *vm, njs_value_t *value,
     njs_value_t *setval, njs_value_t *retval)
 {
     size_t     size;
@@ -3752,15 +3754,15 @@ njs_string_to_c_string(njs_vm_t *vm, njs
 static const njs_object_prop_t  njs_string_prototype_properties[] =
 {
     {
-        .type = NJS_PROPERTY_HANDLER,
-        .name = njs_string("__proto__"),
-        .value = njs_prop_handler(njs_primitive_prototype_get_proto),
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 0, 0.0),
     },
 
     {
         .type = NJS_PROPERTY_HANDLER,
-        .name = njs_string("length"),
-        .value = njs_prop_handler(njs_string_prototype_length),
+        .name = njs_string("__proto__"),
+        .value = njs_prop_handler(njs_primitive_prototype_get_proto),
     },
 
     {
@@ -3973,6 +3975,23 @@ const njs_object_init_t  njs_string_prot
 };
 
 
+const njs_object_prop_t  njs_string_instance_properties[] =
+{
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("length"),
+        .value = njs_prop_handler(njs_string_instance_length),
+    },
+};
+
+
+const njs_object_init_t  njs_string_instance_init = {
+    nxt_string("String instance"),
+    njs_string_instance_properties,
+    nxt_nitems(njs_string_instance_properties),
+};
+
+
 /*
  * encodeURI(string)
  */
@@ -4448,36 +4467,126 @@ njs_value_index(njs_vm_t *vm, const njs_
 }
 
 
+static const njs_object_prop_t  njs_to_string_function_properties[] =
+{
+    /* toString.name == "toString". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("toString"),
+    },
+
+    /* toString.length == 0. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 0, 0.0),
+    },
+};
+
+
 const njs_object_init_t  njs_to_string_function_init = {
     nxt_string("toString"),
-    NULL,
-    0,
+    njs_to_string_function_properties,
+    nxt_nitems(njs_to_string_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_encode_uri_function_properties[] =
+{
+    /* encodeURI.name == "encodeURI". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("encodeURI"),
+    },
+
+    /* encodeURI.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_encode_uri_function_init = {
     nxt_string("encodeURI"),
-    NULL,
-    0,
+    njs_encode_uri_function_properties,
+    nxt_nitems(njs_encode_uri_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_encode_uri_component_function_properties[] =
+{
+    /* encodeURIComponent.name == "encodeURIComponent". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_long_string("encodeURIComponent"),
+    },
+
+    /* encodeURIComponent.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_encode_uri_component_function_init = {
     nxt_string("encodeURIComponent"),
-    NULL,
-    0,
+    njs_encode_uri_component_function_properties,
+    nxt_nitems(njs_encode_uri_component_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_decode_uri_function_properties[] =
+{
+    /* decodeURI.name == "decodeURI". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("decodeURI"),
+    },
+
+    /* decodeURI.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_decode_uri_function_init = {
     nxt_string("decodeURI"),
-    NULL,
-    0,
+    njs_decode_uri_function_properties,
+    nxt_nitems(njs_decode_uri_function_properties),
+};
+
+
+static const njs_object_prop_t  njs_decode_uri_component_function_properties[] =
+{
+    /* decodeURIComponent.name == "decodeURIComponent". */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_long_string("decodeURIComponent"),
+    },
+
+    /* decodeURIComponent.length == 1. */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+    },
 };
 
 
 const njs_object_init_t  njs_decode_uri_component_function_init = {
     nxt_string("decodeURIComponent"),
-    NULL,
-    0,
+    njs_decode_uri_component_function_properties,
+    nxt_nitems(njs_decode_uri_component_function_properties),
 };
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_string.h
--- a/njs/njs_string.h	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_string.h	Fri Apr 12 18:36:02 2019 +0300
@@ -177,6 +177,7 @@ njs_index_t njs_value_index(njs_vm_t *vm
 
 extern const njs_object_init_t  njs_string_constructor_init;
 extern const njs_object_init_t  njs_string_prototype_init;
+extern const njs_object_init_t  njs_string_instance_init;
 
 extern const njs_object_init_t  njs_to_string_function_init;
 extern const njs_object_init_t  njs_encode_uri_function_init;
diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_vm.h
--- a/njs/njs_vm.h	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/njs_vm.h	Fri Apr 12 18:36:02 2019 +0300
@@ -1078,6 +1078,8 @@ struct njs_vm_s {
      */
     njs_object_t             memory_error_object;
 
+    njs_object_t             string_object;
+
     nxt_array_t              *code;  /* of njs_vm_code_t */
 
     nxt_trace_t              trace;
@@ -1108,9 +1110,12 @@ typedef struct {
 struct njs_vm_shared_s {
     nxt_lvlhsh_t             keywords_hash;
     nxt_lvlhsh_t             values_hash;
-    nxt_lvlhsh_t             function_prototype_hash;
-    nxt_lvlhsh_t             arguments_object_hash;
+    nxt_lvlhsh_t             array_instance_hash;
+    nxt_lvlhsh_t             string_instance_hash;
+    nxt_lvlhsh_t             function_instance_hash;
+    nxt_lvlhsh_t             arguments_object_instance_hash;
 
+    njs_object_t             string_object;
     njs_object_t             objects[NJS_OBJECT_MAX];
     njs_function_t           functions[NJS_FUNCTION_MAX];
 
diff -r ff7760036c67 -r 1213e0a2b485 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Apr 11 21:24:16 2019 +0300
+++ b/njs/test/njs_unit_test.c	Fri Apr 12 18:36:02 2019 +0300
@@ -3134,7 +3134,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("true") },
 
     { nxt_string("var a = [1,2]; delete a.length"),
-      nxt_string("false") },
+      nxt_string("TypeError: Cannot delete property \"length\" of array") },
 
     { nxt_string("var a = [1,2,3]; a.x = 10;  delete a[1]"),
       nxt_string("true") },
@@ -5638,6 +5638,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("String.bytesFrom('QUJDRA#', 'base64url')"),
       nxt_string("ABCD") },
 
+    { nxt_string("encodeURI.name"),
+      nxt_string("encodeURI")},
+
+    { nxt_string("encodeURI.length"),
+      nxt_string("1")},
+
     { nxt_string("encodeURI()"),
       nxt_string("undefined")},
 
@@ -5647,9 +5653,21 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("encodeURI('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
       nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B@?%3E=%3C;:/.-,+*)('&%25$#%22!%20")},
 
+    { nxt_string("encodeURIComponent.name"),
+      nxt_string("encodeURIComponent")},
+
+    { nxt_string("encodeURIComponent.length"),
+      nxt_string("1")},
+
     { nxt_string("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
       nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")},
 
+    { nxt_string("decodeURI.name"),
+      nxt_string("decodeURI")},
+
+    { nxt_string("decodeURI.length"),
+      nxt_string("1")},
+
     { nxt_string("decodeURI()"),
       nxt_string("undefined")},
 
@@ -5671,6 +5689,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("decodeURI('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"),
       nxt_string("~}|{`_^]\\[%40%3f>%3d<%3b%3a%2f.%2c%2b*)('%26%%24%23\"! ")},
 
+    { nxt_string("decodeURIComponent.name"),
+      nxt_string("decodeURIComponent")},
+
+    { nxt_string("decodeURIComponent.length"),
+      nxt_string("1")},
+
     { nxt_string("decodeURIComponent('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"),
       nxt_string("~}|{`_^]\\[@?>=<;:/.,+*)('&%$#\"! ")},
 
@@ -7700,6 +7724,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Array.prototype"),
       nxt_string("") },
 
+    { nxt_string("Array.prototype.length"),
+      nxt_string("0") },
+
     { nxt_string("Array.constructor === Function"),
       nxt_string("true") },
 
@@ -8132,6 +8159,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Function.prototype"),
       nxt_string("[object Function]") },
 
+    { nxt_string("Function.prototype.length"),
+      nxt_string("0") },
+
     { nxt_string("Function.constructor === Function"),
       nxt_string("true") },
 
@@ -8801,10 +8831,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("a,b") },
 
     { nxt_string("Object.getOwnPropertyNames(Object.defineProperty([], 'b', {}))"),
-      nxt_string("length,b") },
+      nxt_string("b,length") },
 
     { nxt_string("Object.getOwnPropertyNames(Object.defineProperty(new String(), 'b', {}))"),
-      nxt_string("length,b") },
+      nxt_string("b,length") },
 
     { nxt_string("Object.getOwnPropertyNames([1,2,3])"),
       nxt_string("0,1,2,length") },
@@ -10483,6 +10513,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("isNaN"),
       nxt_string("[object Function]") },
 
+    { nxt_string("isNaN.name"),
+      nxt_string("isNaN") },
+
+    { nxt_string("isNaN.length"),
+      nxt_string("1") },
+
     { nxt_string("isNaN()"),
       nxt_string("true") },
 
@@ -10501,6 +10537,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("isFinite"),
       nxt_string("[object Function]") },
 
+    { nxt_string("isFinite.name"),
+      nxt_string("isFinite") },


More information about the nginx-devel mailing list