]> git.kaiwu.me - njs.git/commitdiff
Fixed objects instance properties.
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 12 Apr 2019 15:36:02 +0000 (18:36 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Fri, 12 Apr 2019 15:36:02 +0000 (18:36 +0300)
Some properties like 'length' of Array, String or Function
objects should be instance properties not prototype properties.

12 files changed:
njs/njs_array.c
njs/njs_array.h
njs/njs_builtin.c
njs/njs_extern.c
njs/njs_function.c
njs/njs_function.h
njs/njs_number.c
njs/njs_object.c
njs/njs_string.c
njs/njs_string.h
njs/njs_vm.h
njs/test/njs_unit_test.c

index f605428a5acdd4003ebf0b2c4c5a00011d3f6208..635561b47887abb545484007f36a6177301988cd 100644 (file)
@@ -149,7 +149,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare)
 
     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_constructor_init = {
 
 
 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_array_prototype_properties[] =
     {
         .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_prototype_init = {
     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),
+};
index d2c06f7a4c91e012f5b83c35a3b981a339a92c98..5d13a8b3faa58e2f7b484723d31e6a4ff4802b24 100644 (file)
@@ -26,6 +26,7 @@ njs_ret_t njs_array_constructor(njs_vm_t *vm, njs_value_t *args,
 
 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_ */
index 82ecd6ee4cf38760be3da344dcdbf96a98a99971..56edb72648b76fb46d3dc8941aa5784f5b5d3893 100644 (file)
@@ -138,22 +138,6 @@ const njs_function_init_t  njs_native_functions[] = {
 };
 
 
-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_prototype_values[] = {
 };
 
 
+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_init(vm, &shared->function_instance_hash,
+                               &njs_function_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->arguments_object_instance_hash,
+                               &njs_arguments_object_instance_init);
     if (nxt_slow_path(ret != NXT_OK)) {
         return NXT_ERROR;
     }
 
-    object = vm->shared->objects;
+    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;
 }
 
index c46003143ac8f1bf6cda433f7352e73cf6156a16..66cf27d35a2ff727f09420ab97c881f432eba2d2 100644 (file)
@@ -109,7 +109,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lvlhsh_t *hash, njs_external_t *external,
 
             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;
index a3435d68d433228a59c931d4ea5c106f107dc5a0..03e65a067ae304a61b0240aaab4c6b312b7c4e06 100644 (file)
@@ -42,7 +42,7 @@ njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda,
     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_vm_t *vm, njs_native_frame_t *frame)
         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_t *vm, njs_native_frame_t *frame)
 }
 
 
-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 *vm, njs_value_t *value,
 }
 
 
+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_constructor_init = {
  *      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, njs_value_t *args, nxt_uint_t nargs,
 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_prototype_init = {
 };
 
 
+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)
index 6d54b83895f60e3de4123da63b15b51d559a3383..05b54531629719e79cfe10a79bb99dc050fc63d4 100644 (file)
@@ -153,8 +153,6 @@ njs_ret_t njs_function_arguments_object_init(njs_vm_t *vm,
     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_frame_t *frame)
 
 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);
index 3f8c116561874b4c147859c3a658c1fd441b95de..3a89c4dbd870ada079117f946dac5c67f352daf4 100644 (file)
@@ -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),
 };
index f2a0f38ea85316d9f41c38f35a14fd75d2c242ca..8c2126f9bb5c736efe2f5b63e4725abb9d40de50 100644 (file)
@@ -294,7 +294,7 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
             }
         }
 
-        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, njs_property_query_t *pq)
         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 njs_value_t *value,
             }
         }
 
-        exotic_length = all;
-
         break;
 
     case NJS_STRING:
@@ -997,19 +992,14 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
 
         } 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 njs_value_t *value,
     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 njs_value_t *value,
 
         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 njs_value_t *value,
         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 njs_value_t *value,
         }
     }
 
-    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 njs_value_t *value,
 
             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);
index 4ccd3aa903f0ef57ffb7d31812a7a5a21c229e04..36e95dac82ddaa4715a7a59a64f21fb15c71bb71 100644 (file)
@@ -555,6 +555,8 @@ njs_string_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
             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_constructor_init = {
 
 
 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_value_t *value)
 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_prototype_init = {
 };
 
 
+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_value_t *src, nxt_uint_t runtime)
 }
 
 
+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),
 };
index 314f76f325e683f0046823c457ccc0d917f01351..d70a7dc0a963e2234193db2602db1818f82e2336 100644 (file)
@@ -177,6 +177,7 @@ njs_index_t njs_value_index(njs_vm_t *vm, const njs_value_t *src,
 
 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;
index 8f3c9975ef7b6a3d91e159c70faa34585da8c0ba..565620e4287d616c641c0e65fb2dbc0a19ae8a3f 100644 (file)
@@ -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];
 
index ede03192a4d01c91b76abc4a5ea5ad45b9a8be80..6e1d9d86a247c7cc550e0317162dac7f650ec2ca 100644 (file)
@@ -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") },
+
+    { nxt_string("isFinite.length"),
+      nxt_string("1") },
+
     { nxt_string("isFinite()"),
       nxt_string("false") },
 
@@ -10516,6 +10558,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("isFinite('abc')"),
       nxt_string("false") },
 
+    { nxt_string("parseInt.name"),
+      nxt_string("parseInt") },
+
+    { nxt_string("parseInt.length"),
+      nxt_string("2") },
+
     { nxt_string("parseInt('12345abc')"),
       nxt_string("12345") },
 
@@ -10567,6 +10615,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("parseInt('0', 37)"),
       nxt_string("NaN") },
 
+    { nxt_string("parseFloat.name"),
+      nxt_string("parseFloat") },
+
+    { nxt_string("parseFloat.length"),
+      nxt_string("1") },
+
     { nxt_string("parseFloat('12345abc')"),
       nxt_string("12345") },