]> git.kaiwu.me - njs.git/commitdiff
Getting rid of special types for primitive objects.
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 2 Nov 2021 12:37:00 +0000 (12:37 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 2 Nov 2021 12:37:00 +0000 (12:37 +0000)
The following types were removed: NJS_OBJECT_BOOLEAN,
NJS_OBJECT_NUMBER, NJS_OBJECT_SYMBOL, NJS_OBJECT_STRING.

Instead a generic NJS_OBJECT_VALUE type is used for objects
with custom slots.

15 files changed:
src/njs_array.c
src/njs_boolean.c
src/njs_builtin.c
src/njs_iterator.c
src/njs_json.c
src/njs_number.c
src/njs_object.c
src/njs_object.h
src/njs_string.c
src/njs_symbol.c
src/njs_value.c
src/njs_value.h
src/njs_value_conversion.h
src/njs_vmcode.c
src/test/njs_unit_test.c

index 07b7fe48fb6e4d3f24237c35ac9544976d7b2f8b..9b4b05ee4617f29dcc593081a665c7f18c5734ed 100644 (file)
@@ -775,9 +775,9 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
                 length--;
             } while (length != 0);
 
-        } else if (njs_is_string(this) || this->type == NJS_OBJECT_STRING) {
+        } else if (njs_is_string(this) || njs_is_object_string(this)) {
 
-            if (this->type == NJS_OBJECT_STRING) {
+            if (njs_is_object_string(this)) {
                 this = njs_object_value(this);
             }
 
index 48d52d5891277f0325fdb05c1c95d495e78c9f05..7b0cc5c952584e35129079ae1f1103116b855b7c 100644 (file)
@@ -12,8 +12,8 @@ static njs_int_t
 njs_boolean_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_object_t       *object;
-    const njs_value_t  *value;
+    const njs_value_t   *value;
+    njs_object_value_t  *object;
 
     if (nargs == 1) {
         value = &njs_value_false;
@@ -23,12 +23,12 @@ njs_boolean_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (vm->top_frame->ctor) {
-        object = njs_object_value_alloc(vm, value, value->type);
+        object = njs_object_value_alloc(vm, NJS_OBJ_TYPE_BOOLEAN, 0, value);
         if (njs_slow_path(object == NULL)) {
             return NJS_ERROR;
         }
 
-        njs_set_type_object(&vm->retval, object, NJS_OBJECT_BOOLEAN);
+        njs_set_object_value(&vm->retval, object);
 
     } else {
         vm->retval = *value;
@@ -78,7 +78,7 @@ njs_boolean_prototype_value_of(njs_vm_t *vm, njs_value_t *args,
 
     if (value->type != NJS_BOOLEAN) {
 
-        if (value->type == NJS_OBJECT_BOOLEAN) {
+        if (njs_is_object_boolean(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -104,7 +104,7 @@ njs_boolean_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
 
     if (value->type != NJS_BOOLEAN) {
 
-        if (value->type == NJS_OBJECT_BOOLEAN) {
+        if (njs_is_object_boolean(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -168,6 +168,6 @@ const njs_object_type_init_t  njs_boolean_type_init = {
    .prototype_props = &njs_boolean_prototype_init,
    .prototype_value = { .object_value = {
                             .value = njs_value(NJS_BOOLEAN, 0, 0.0),
-                            .object = { .type = NJS_OBJECT_BOOLEAN } }
+                            .object = { .type = NJS_OBJECT_VALUE } }
                       },
 };
index 4e48d6aba887cea67cda9f7580594a87e372c39c..f4868491f1c40a3dcab0b2544735217e8ab5121a 100644 (file)
@@ -333,7 +333,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
     string_object = &shared->string_object;
     njs_lvlhsh_init(&string_object->hash);
     string_object->shared_hash = shared->string_instance_hash;
-    string_object->type = NJS_OBJECT_STRING;
+    string_object->type = NJS_OBJECT_VALUE;
     string_object->shared = 1;
     string_object->extensible = 0;
 
index 4faa1cde31f68e02de99e66eecc6d5f519ba9a09..ca2dd973f36042a4a2e99e8eda7e003d17f73e90 100644 (file)
@@ -311,14 +311,14 @@ njs_int_t
 njs_object_iterate(njs_vm_t *vm, njs_iterator_args_t *args,
     njs_iterator_handler_t handler)
 {
-    double             idx;
-    int64_t            length, i, from, to;
-    njs_int_t          ret;
-    njs_array_t        *array, *keys;
-    njs_value_t        *value, *entry, prop, character, string_obj;
-    njs_object_t       *object;
-    const u_char       *p, *end, *pos;
-    njs_string_prop_t  string_prop;
+    double              idx;
+    int64_t             length, i, from, to;
+    njs_int_t           ret;
+    njs_array_t         *array, *keys;
+    njs_value_t         *value, *entry, prop, character, string_obj;
+    const u_char        *p, *end, *pos;
+    njs_string_prop_t   string_prop;
+    njs_object_value_t  *object;
 
     value = args->value;
     from = args->from;
@@ -366,12 +366,12 @@ njs_object_iterate(njs_vm_t *vm, njs_iterator_args_t *args,
     if (njs_is_string(value) || njs_is_object_string(value)) {
 
         if (njs_is_string(value)) {
-            object = njs_object_value_alloc(vm, value, NJS_STRING);
+            object = njs_object_value_alloc(vm, NJS_OBJ_TYPE_STRING, 0, value);
             if (njs_slow_path(object == NULL)) {
                 return NJS_ERROR;
             }
 
-            njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
+            njs_set_object_value(&string_obj, object);
 
             args->value = &string_obj;
         }
@@ -473,14 +473,14 @@ njs_int_t
 njs_object_iterate_reverse(njs_vm_t *vm, njs_iterator_args_t *args,
     njs_iterator_handler_t handler)
 {
-    double             idx;
-    int64_t            i, from, to, length;
-    njs_int_t          ret;
-    njs_array_t        *array, *keys;
-    njs_value_t        *entry, *value, prop, character, string_obj;
-    njs_object_t       *object;
-    const u_char       *p, *end, *pos;
-    njs_string_prop_t  string_prop;
+    double              idx;
+    int64_t             i, from, to, length;
+    njs_int_t           ret;
+    njs_array_t         *array, *keys;
+    njs_value_t         *entry, *value, prop, character, string_obj;
+    const u_char        *p, *end, *pos;
+    njs_string_prop_t   string_prop;
+    njs_object_value_t  *object;
 
     value = args->value;
     from = args->from;
@@ -530,12 +530,12 @@ njs_object_iterate_reverse(njs_vm_t *vm, njs_iterator_args_t *args,
     if (njs_is_string(value) || njs_is_object_string(value)) {
 
         if (njs_is_string(value)) {
-            object = njs_object_value_alloc(vm, value, NJS_STRING);
+            object = njs_object_value_alloc(vm, NJS_OBJ_TYPE_STRING, 0, value);
             if (njs_slow_path(object == NULL)) {
                 return NJS_ERROR;
             }
 
-            njs_set_type_object(&string_obj, object, NJS_OBJECT_STRING);
+            njs_set_object_value(&string_obj, object);
 
             args->value = &string_obj;
         }
index 56df4e77bb9fa7da48c74f50f7b73cafc39caea4..90f1f517bb6df8a8cbdde4f3b67b7fade657b0ac 100644 (file)
@@ -220,15 +220,22 @@ njs_json_stringify(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     space = njs_arg(args, nargs, 3);
 
-    switch (space->type) {
-    case NJS_OBJECT_STRING:
-        ret = njs_value_to_string(vm, space, space);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+    if (njs_is_object(space)) {
+        if (njs_is_object_number(space)) {
+            ret = njs_value_to_numeric(vm, space, space);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return ret;
+            }
 
-        /* Fall through. */
+        } else if (njs_is_object_string(space)) {
+            ret = njs_value_to_string(vm, space, space);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return ret;
+            }
+        }
+    }
 
+    switch (space->type) {
     case NJS_STRING:
         length = njs_string_prop(&prop, space);
 
@@ -250,14 +257,6 @@ njs_json_stringify(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         break;
 
-    case NJS_OBJECT_NUMBER:
-        ret = njs_value_to_numeric(vm, space, space);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
-        /* Fall through. */
-
     case NJS_NUMBER:
         i64 = njs_min(njs_number_to_integer(njs_number(space)), 10);
 
@@ -1138,10 +1137,27 @@ njs_json_pop_stringify_state(njs_json_stringify_t *stringify)
 njs_inline njs_bool_t
 njs_json_is_object(const njs_value_t *value)
 {
-    return (((value)->type == NJS_OBJECT)
-             || ((value)->type == NJS_ARRAY)
-             || ((value)->type == NJS_OBJECT_SYMBOL)
-             || ((value)->type >= NJS_REGEXP));
+    if (!njs_is_object(value)) {
+        return 0;
+    }
+
+    if (njs_is_function(value)) {
+        return 0;
+    }
+
+    if (njs_is_object_value(value)) {
+        switch (njs_object_value(value)->type) {
+        case NJS_BOOLEAN:
+        case NJS_NUMBER:
+        case NJS_STRING:
+            return 0;
+
+        default:
+            break;
+        }
+    }
+
+    return 1;
 }
 
 
@@ -1487,74 +1503,82 @@ static njs_int_t
 njs_json_stringify_array(njs_vm_t *vm, njs_json_stringify_t *stringify)
 {
     njs_int_t    ret;
-    uint32_t     i, n, k, properties_length, array_length;
-    njs_value_t  *value, num_value;
-    njs_array_t  *properties, *array;
+    int64_t      i, k, length;
+    njs_value_t  *value, *item;
+    njs_array_t  *properties;
 
-    properties_length = 1;
-    array = njs_array(&stringify->replacer);
-    array_length = array->length;
-
-    for (i = 0; i < array_length; i++) {
-        if (njs_is_valid(&array->start[i])) {
-            properties_length++;
-        }
+    ret = njs_object_length(vm, &stringify->replacer, &length);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
     }
 
-    properties = njs_array_alloc(vm, 1, properties_length, NJS_ARRAY_SPARE);
+    properties = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE);
     if (njs_slow_path(properties == NULL)) {
         return NJS_ERROR;
     }
 
-    n = 0;
-    properties->start[n++] = njs_string_empty;
-
-    for (i = 0; i < array_length; i++) {
-        value = &array->start[i];
+    item = njs_array_push(vm, properties);
+    njs_value_assign(item, &njs_string_empty);
 
-        if (!njs_is_valid(&array->start[i])) {
-            continue;
+    for (i = 0; i < length; i++) {
+        ret = njs_value_property_i64(vm, &stringify->replacer, i,
+                                     &stringify->retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
         }
 
+        value = &stringify->retval;
+
         switch (value->type) {
+        case NJS_STRING:
+            break;
+
         case NJS_NUMBER:
-            ret = njs_number_to_string(vm, &num_value, value);
+            ret = njs_number_to_string(vm, value, value);
             if (njs_slow_path(ret != NJS_OK)) {
                 return NJS_ERROR;
             }
 
-            value = &num_value;
             break;
 
-        case NJS_OBJECT_NUMBER:
-        case NJS_OBJECT_STRING:
-            ret = njs_value_to_string(vm, value, value);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return NJS_ERROR;
-            }
+        case NJS_OBJECT_VALUE:
+            switch (njs_object_value(value)->type) {
+            case NJS_NUMBER:
+            case NJS_STRING:
+                ret = njs_value_to_string(vm, value, value);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return NJS_ERROR;
+                }
+
+                break;
 
-            /* Fall through. */
+            default:
+                continue;
+            }
 
-        case NJS_STRING:
             break;
 
         default:
             continue;
         }
 
-        for (k = 0; k < n; k ++) {
+        for (k = 0; k < properties->length; k++) {
             if (njs_values_strict_equal(value, &properties->start[k]) == 1) {
                 break;
             }
         }
 
-        if (k == n) {
-            properties->start[n++] = *value;
+        if (k == properties->length) {
+            item = njs_array_push(vm, properties);
+            if (njs_slow_path(item == NULL)) {
+                return NJS_ERROR;
+            }
+
+            njs_value_assign(item, value);
         }
     }
 
-    properties->length = n;
-    stringify->replacer.data.u.array = properties;
+    njs_set_array(&stringify->replacer, properties);
 
     return NJS_OK;
 }
@@ -1565,35 +1589,42 @@ njs_json_append_value(njs_vm_t *vm, njs_chb_t *chain, njs_value_t *value)
 {
     njs_int_t  ret;
 
-    switch (value->type) {
-    case NJS_OBJECT_STRING:
-         ret = njs_value_to_string(vm, value, value);
-         if (njs_slow_path(ret != NJS_OK)) {
-             return ret;
-         }
+    if (njs_is_object_value(value)) {
+        switch (njs_object_value(value)->type) {
+        case NJS_NUMBER:
+            ret = njs_value_to_numeric(vm, value, value);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return ret;
+            }
 
-        /* Fall through. */
+            break;
+
+        case NJS_BOOLEAN:
+            njs_value_assign(value, njs_object_value(value));
+            break;
+
+        case NJS_STRING:
+            ret = njs_value_to_string(vm, value, value);
+             if (njs_slow_path(ret != NJS_OK)) {
+                 return ret;
+             }
+
+            break;
 
+        default:
+            break;
+        }
+    }
+
+    switch (value->type) {
     case NJS_STRING:
         njs_json_append_string(chain, value, '\"');
         break;
 
-    case NJS_OBJECT_NUMBER:
-         ret = njs_value_to_numeric(vm, value, value);
-         if (njs_slow_path(ret != NJS_OK)) {
-             return ret;
-         }
-
-        /* Fall through. */
-
     case NJS_NUMBER:
         njs_json_append_number(chain, value);
         break;
 
-    case NJS_OBJECT_BOOLEAN:
-        value = njs_object_value(value);
-        /* Fall through. */
-
     case NJS_BOOLEAN:
         if (njs_is_true(value)) {
             njs_chb_append_literal(chain, "true");
@@ -1829,12 +1860,22 @@ njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
     njs_int_t   (*to_string)(njs_vm_t *, njs_value_t *, const njs_value_t *);
 
     switch (value->type) {
-    case NJS_OBJECT_STRING:
-        value = njs_object_value(value);
+    case NJS_NULL:
+        njs_chb_append_literal(chain, "null");
+        break;
+
+    case NJS_UNDEFINED:
+        njs_chb_append_literal(chain, "undefined");
+        break;
+
+    case NJS_BOOLEAN:
+        if (njs_is_true(value)) {
+            njs_chb_append_literal(chain, "true");
+
+        } else {
+            njs_chb_append_literal(chain, "false");
+        }
 
-        njs_chb_append_literal(chain, "[String: ");
-        njs_json_append_string(chain, value, '\'');
-        njs_chb_append_literal(chain, "]");
         break;
 
     case NJS_STRING:
@@ -1849,19 +1890,6 @@ njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
 
         break;
 
-    case NJS_OBJECT_SYMBOL:
-        value = njs_object_value(value);
-
-        ret = njs_symbol_descriptive_string(stringify->vm, &str_val, value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
-
-        njs_string_get(&str_val, &str);
-        njs_chb_sprintf(chain, 16 + str.length, "[Symbol: %V]", &str);
-
-        break;
-
     case NJS_SYMBOL:
         ret = njs_symbol_descriptive_string(stringify->vm, &str_val, value);
         if (njs_slow_path(ret != NJS_OK)) {
@@ -1873,61 +1901,63 @@ njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
 
         break;
 
-    case NJS_OBJECT_NUMBER:
+    case NJS_INVALID:
+        njs_chb_append_literal(chain, "<empty>");
+        break;
+
+    case NJS_OBJECT_VALUE:
         value = njs_object_value(value);
 
-        if (njs_slow_path(njs_number(value) == 0.0
-                          && signbit(njs_number(value))))
-        {
+        switch (value->type) {
+        case NJS_BOOLEAN:
+            if (njs_is_true(value)) {
+                njs_chb_append_literal(chain, "[Boolean: true]");
 
-            njs_chb_append_literal(chain, "[Number: -0]");
-            break;
-        }
+            } else {
+                njs_chb_append_literal(chain, "[Boolean: false]");
+            }
 
-        ret = njs_number_to_string(stringify->vm, &str_val, value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
+            break;
 
-        njs_string_get(&str_val, &str);
-        njs_chb_sprintf(chain, 16 + str.length, "[Number: %V]", &str);
+        case NJS_NUMBER:
+            if (njs_slow_path(njs_number(value) == 0.0
+                              && signbit(njs_number(value))))
+            {
 
-        break;
+                njs_chb_append_literal(chain, "[Number: -0]");
+                break;
+            }
 
-    case NJS_OBJECT_BOOLEAN:
-        value = njs_object_value(value);
+            ret = njs_number_to_string(stringify->vm, &str_val, value);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
 
-        if (njs_is_true(value)) {
-            njs_chb_append_literal(chain, "[Boolean: true]");
+            njs_string_get(&str_val, &str);
+            njs_chb_sprintf(chain, 16 + str.length, "[Number: %V]", &str);
+            break;
 
-        } else {
-            njs_chb_append_literal(chain, "[Boolean: false]");
-        }
+        case NJS_SYMBOL:
+            ret = njs_symbol_descriptive_string(stringify->vm, &str_val, value);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
 
-        break;
+            njs_string_get(&str_val, &str);
+            njs_chb_sprintf(chain, 16 + str.length, "[Symbol: %V]", &str);
 
-    case NJS_BOOLEAN:
-        if (njs_is_true(value)) {
-            njs_chb_append_literal(chain, "true");
+            break;
 
-        } else {
-            njs_chb_append_literal(chain, "false");
+        case NJS_STRING:
+        default:
+            njs_chb_append_literal(chain, "[String: ");
+            njs_json_append_string(chain, value, '\'');
+            njs_chb_append_literal(chain, "]");
+            break;
         }
 
         break;
 
-    case NJS_UNDEFINED:
-        njs_chb_append_literal(chain, "undefined");
-        break;
-
-    case NJS_NULL:
-        njs_chb_append_literal(chain, "null");
-        break;
-
-    case NJS_INVALID:
-        njs_chb_append_literal(chain, "<empty>");
-        break;
-
     case NJS_FUNCTION:
         ret = njs_value_property(stringify->vm, value,
                                  njs_value_arg(&name_string), &tag);
@@ -2031,7 +2061,8 @@ njs_dump_is_recursive(const njs_value_t *value)
 {
     return (value->type == NJS_OBJECT && !njs_object(value)->error_data)
            || (value->type == NJS_ARRAY)
-           || (value->type >= NJS_OBJECT_SPECIAL_MAX);
+           || (value->type >= NJS_OBJECT_SPECIAL_MAX
+               && !njs_is_object_primitive(value));
 }
 
 
index 276b95b28ee759f77dc8d219a2b43aff6c32fa8c..68d825569b78d151acf99fef16ab10a987963ef8 100644 (file)
@@ -311,9 +311,9 @@ static njs_int_t
 njs_number_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_int_t     ret;
-    njs_value_t   *value;
-    njs_object_t  *object;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    njs_object_value_t  *object;
 
     if (nargs == 1) {
         value = njs_value_arg(&njs_value_zero);
@@ -330,12 +330,12 @@ njs_number_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (vm->top_frame->ctor) {
-        object = njs_object_value_alloc(vm, value, NJS_NUMBER);
+        object = njs_object_value_alloc(vm, NJS_OBJ_TYPE_NUMBER, 0, value);
         if (njs_slow_path(object == NULL)) {
             return NJS_ERROR;
         }
 
-        njs_set_type_object(&vm->retval, object, NJS_OBJECT_NUMBER);
+        njs_set_object_value(&vm->retval, object);
 
     } else {
         njs_set_number(&vm->retval, njs_number(value));
@@ -572,7 +572,7 @@ njs_number_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     if (value->type != NJS_NUMBER) {
 
-        if (value->type == NJS_OBJECT_NUMBER) {
+        if (njs_is_object_number(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -601,7 +601,7 @@ njs_number_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
 
     if (value->type != NJS_NUMBER) {
 
-        if (value->type == NJS_OBJECT_NUMBER) {
+        if (njs_is_object_number(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -650,7 +650,7 @@ njs_number_prototype_to_fixed(njs_vm_t *vm, njs_value_t *args,
     value = &args[0];
 
     if (value->type != NJS_NUMBER) {
-        if (value->type == NJS_OBJECT_NUMBER) {
+        if (njs_is_object_number(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -748,7 +748,7 @@ njs_number_prototype_to_precision(njs_vm_t *vm, njs_value_t *args,
     value = &args[0];
 
     if (value->type != NJS_NUMBER) {
-        if (value->type == NJS_OBJECT_NUMBER) {
+        if (njs_is_object_number(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -798,7 +798,7 @@ njs_number_prototype_to_exponential(njs_vm_t *vm, njs_value_t *args,
     value = &args[0];
 
     if (value->type != NJS_NUMBER) {
-        if (value->type == NJS_OBJECT_NUMBER) {
+        if (njs_is_object_number(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -1187,6 +1187,6 @@ const njs_object_type_init_t  njs_number_type_init = {
    .prototype_props = &njs_number_prototype_init,
    .prototype_value = { .object_value = {
                             .value = njs_value(NJS_NUMBER, 0, 0.0),
-                            .object = { .type = NJS_OBJECT_NUMBER } }
+                            .object = { .type = NJS_OBJECT_VALUE } }
                       },
 };
index 02ba69ae9f835eba140ec461ad2ebc7a35a9368d..454e7e77cf9a4f0776fa390add25983d0e67660e 100644 (file)
@@ -92,42 +92,41 @@ njs_object_value_copy(njs_vm_t *vm, njs_value_t *value)
 }
 
 
-njs_object_t *
-njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, njs_uint_t type)
+njs_object_value_t *
+njs_object_value_alloc(njs_vm_t *vm, njs_uint_t prototype_index, size_t extra,
+    const njs_value_t *value)
 {
-    njs_uint_t          index;
     njs_object_value_t  *ov;
 
-    ov = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_value_t));
+    ov = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_value_t) + extra);
+    if (njs_slow_path(ov == NULL)) {
+        njs_memory_error(vm);
+        return NULL;
+    }
 
-    if (njs_fast_path(ov != NULL)) {
-        njs_lvlhsh_init(&ov->object.hash);
+    njs_lvlhsh_init(&ov->object.hash);
 
-        if (type == NJS_STRING) {
-            ov->object.shared_hash = vm->shared->string_instance_hash;
+    if (prototype_index == NJS_OBJ_TYPE_STRING) {
+        ov->object.shared_hash = vm->shared->string_instance_hash;
 
-        } else {
-            njs_lvlhsh_init(&ov->object.shared_hash);
-        }
+    } else {
+        njs_lvlhsh_init(&ov->object.shared_hash);
+    }
 
-        ov->object.type = njs_object_value_type(type);
-        ov->object.shared = 0;
-        ov->object.extensible = 1;
-        ov->object.error_data = 0;
-        ov->object.fast_array = 0;
+    ov->object.type = NJS_OBJECT_VALUE;
+    ov->object.shared = 0;
+    ov->object.extensible = 1;
+    ov->object.error_data = 0;
+    ov->object.fast_array = 0;
 
-        index = njs_primitive_prototype_index(type);
-        ov->object.__proto__ = &vm->prototypes[index].object;
-        ov->object.slots = NULL;
+    ov->object.__proto__ = &vm->prototypes[prototype_index].object;
+    ov->object.slots = NULL;
 
+    if (value != NULL) {
         ov->value = *value;
-
-        return &ov->object;
     }
 
-    njs_memory_error(vm);
-
-    return NULL;
+    return ov;
 }
 
 
@@ -219,46 +218,45 @@ static njs_int_t
 njs_object_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_uint_t    type;
-    njs_value_t   *value;
-    njs_object_t  *object;
+    njs_uint_t          type, index;
+    njs_value_t         *value;
+    njs_object_t        *object;
+    njs_object_value_t  *obj_val;
 
     value = njs_arg(args, nargs, 1);
     type = value->type;
 
     if (njs_is_null_or_undefined(value)) {
-
         object = njs_object_alloc(vm);
         if (njs_slow_path(object == NULL)) {
             return NJS_ERROR;
         }
 
-        type = NJS_OBJECT;
-
-    } else {
+        njs_set_object(&vm->retval, object);
 
-        if (njs_is_object(value)) {
-            object = njs_object(value);
+        return NJS_OK;
+    }
 
-        } else if (njs_is_primitive(value)) {
+    if (njs_is_primitive(value)) {
+        index = njs_primitive_prototype_index(type);
+        obj_val = njs_object_value_alloc(vm, index, 0, value);
+        if (njs_slow_path(obj_val == NULL)) {
+            return NJS_ERROR;
+        }
 
-            /* value->type is the same as prototype offset. */
-            object = njs_object_value_alloc(vm, value, type);
-            if (njs_slow_path(object == NULL)) {
-                return NJS_ERROR;
-            }
+        njs_set_object_value(&vm->retval, obj_val);
 
-            type = njs_object_value_type(type);
+        return NJS_OK;
+    }
 
-        } else {
-            njs_type_error(vm, "unexpected constructor argument:%s",
-                           njs_type_string(type));
+    if (njs_slow_path(!njs_is_object(value))) {
+        njs_type_error(vm, "unexpected constructor argument:%s",
+                       njs_type_string(type));
 
-            return NJS_ERROR;
-        }
+        return NJS_ERROR;
     }
 
-    njs_set_type_object(&vm->retval, object, type);
+    njs_value_assign(&vm->retval, value);
 
     return NJS_OK;
 }
@@ -450,11 +448,16 @@ njs_object_enumerate_value(njs_vm_t *vm, const njs_object_t *object,
                                                   items, kind);
             break;
 
-        case NJS_OBJECT_STRING:
+        case NJS_OBJECT_VALUE:
             obj_val = (njs_object_value_t *) object;
 
-            ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind);
-            break;
+            if (njs_is_string(&obj_val->value)) {
+                ret = njs_object_enumerate_string(vm, &obj_val->value, items,
+                                                  kind);
+                break;
+            }
+
+        /* Fall through. */
 
         default:
             goto object;
@@ -497,11 +500,16 @@ njs_object_own_enumerate_value(njs_vm_t *vm, const njs_object_t *object,
                                                    items, kind);
             break;
 
-        case NJS_OBJECT_STRING:
+        case NJS_OBJECT_VALUE:
             obj_val = (njs_object_value_t *) object;
 
-            ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind);
-            break;
+            if (njs_is_string(&obj_val->value)) {
+                ret = njs_object_enumerate_string(vm, &obj_val->value, items,
+                                                  kind);
+                break;
+            }
+
+            /* Fall through. */
 
         default:
             goto object;
@@ -1462,7 +1470,7 @@ static njs_int_t
 njs_object_get_prototype_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t     index, type;
+    uint32_t     index;
     njs_value_t  *value;
 
     value = njs_arg(args, nargs, 1);
@@ -1474,10 +1482,14 @@ njs_object_get_prototype_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     if (!njs_is_null_or_undefined(value)) {
         index = njs_primitive_prototype_index(value->type);
-        type = njs_is_symbol(value) ? NJS_OBJECT
-                                    : njs_object_value_type(value->type);
 
-        njs_set_type_object(&vm->retval, &vm->prototypes[index].object, type);
+        if (njs_is_symbol(value)) {
+            njs_set_object(&vm->retval, &vm->prototypes[index].object);
+
+        } else {
+            njs_set_object_value(&vm->retval,
+                                 &vm->prototypes[index].object_value);
+        }
 
         return NJS_OK;
     }
@@ -2300,14 +2312,8 @@ static const njs_value_t  njs_object_boolean_string =
                                      njs_long_string("[object Boolean]");
 static const njs_value_t  njs_object_number_string =
                                      njs_long_string("[object Number]");
-static const njs_value_t  njs_object_symbol_string =
-                                     njs_long_string("[object Symbol]");
 static const njs_value_t  njs_object_string_string =
                                      njs_long_string("[object String]");
-static const njs_value_t  njs_object_data_string =
-                                     njs_string("[object Data]");
-static const njs_value_t  njs_object_exernal_string =
-                                     njs_long_string("[object External]");
 static const njs_value_t  njs_object_object_string =
                                      njs_long_string("[object Object]");
 static const njs_value_t  njs_object_array_string =
@@ -2329,67 +2335,68 @@ njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
 {
     u_char             *p;
     njs_int_t          ret;
-    njs_value_t        tag, *value;
+    njs_value_t        tag, *this;
     njs_string_prop_t  string;
     const njs_value_t  *name;
 
-    static const njs_value_t  *class_name[NJS_VALUE_TYPE_MAX] = {
-        /* Primitives. */
-        &njs_object_null_string,
-        &njs_object_undefined_string,
-        &njs_object_boolean_string,
-        &njs_object_number_string,
-        &njs_object_symbol_string,
-        &njs_object_string_string,
-
-        &njs_object_data_string,
-        &njs_object_exernal_string,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-
-        /* Objects. */
-        &njs_object_object_string,
-        &njs_object_array_string,
-        &njs_object_boolean_string,
-        &njs_object_number_string,
-        &njs_object_symbol_string,
-        &njs_object_string_string,
-        &njs_object_function_string,
-        &njs_object_regexp_string,
-        &njs_object_date_string,
-        &njs_object_object_string,
-        &njs_object_object_string,
-        &njs_object_object_string,
-        &njs_object_object_string,
-    };
-
-    value = njs_argument(args, 0);
-    name = class_name[value->type];
+    this = njs_argument(args, 0);
 
-    if (njs_is_null_or_undefined(value)) {
-        vm->retval = *name;
+    if (njs_is_null_or_undefined(this)) {
+        vm->retval = njs_is_null(this) ? njs_object_null_string
+                                       : njs_object_undefined_string;
 
         return NJS_OK;
     }
 
-    if (njs_is_error(value)) {
-        name = &njs_object_error_string;
+    ret = njs_value_to_object(vm, this);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
     }
 
-    if (njs_is_object(value)
-        && njs_lvlhsh_eq(&njs_object(value)->shared_hash,
+    name = &njs_object_object_string;
+
+    if (njs_is_array(this)) {
+        name = &njs_object_array_string;
+
+    } else if (njs_is_object(this)
+        && njs_lvlhsh_eq(&njs_object(this)->shared_hash,
                          &vm->shared->arguments_object_instance_hash))
     {
         name = &njs_object_arguments_string;
+
+    } else if (njs_is_function(this)) {
+        name = &njs_object_function_string;
+
+    } else if (njs_is_error(this)) {
+        name = &njs_object_error_string;
+
+    } else if (njs_is_object_value(this)) {
+
+        switch (njs_object_value(this)->type) {
+        case NJS_BOOLEAN:
+            name = &njs_object_boolean_string;
+            break;
+
+        case NJS_NUMBER:
+            name = &njs_object_number_string;
+            break;
+
+        case NJS_STRING:
+            name = &njs_object_string_string;
+            break;
+
+        default:
+            break;
+        }
+
+    } else if (njs_is_date(this)) {
+        name = &njs_object_date_string;
+
+    } else if (njs_is_regexp(this)) {
+        name = &njs_object_regexp_string;
     }
 
-    ret = njs_object_string_tag(vm, value, &tag);
+    ret = njs_object_string_tag(vm, this, &tag);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
     }
index 95d17aff58899d253667adc8e2f0574393f7e347..85d6fde7e2a72107af373b5e068fd6d1e2cccef5 100644 (file)
@@ -41,8 +41,8 @@ typedef njs_int_t (*njs_object_traverse_cb_t)(njs_vm_t *vm,
 
 njs_object_t *njs_object_alloc(njs_vm_t *vm);
 njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value);
-njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
-    njs_uint_t type);
+njs_object_value_t *njs_object_value_alloc(njs_vm_t *vm, njs_uint_t index,
+    size_t extra,const njs_value_t *value);
 njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object,
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
 njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
@@ -189,7 +189,7 @@ njs_value_to_key(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
     njs_value_t  primitive;
 
     if (njs_slow_path(!njs_is_primitive(value))) {
-        if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
+        if (njs_slow_path(njs_is_object_symbol(value))) {
             /* should fail */
             value = njs_object_value(value);
 
index 871561bf259ec4f97c6cba17632815fb40d32b5a..a3e8da67738955fa62d494d5bd3b5624237d1324 100644 (file)
@@ -570,9 +570,9 @@ static njs_int_t
 njs_string_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_int_t     ret;
-    njs_value_t   *value;
-    njs_object_t  *object;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    njs_object_value_t  *object;
 
     if (nargs == 1) {
         value = njs_value_arg(&njs_string_empty);
@@ -593,12 +593,12 @@ njs_string_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (vm->top_frame->ctor) {
-        object = njs_object_value_alloc(vm, value, value->type);
+        object = njs_object_value_alloc(vm, NJS_OBJ_TYPE_STRING, 0, value);
         if (njs_slow_path(object == NULL)) {
             return NJS_ERROR;
         }
 
-        njs_set_type_object(&vm->retval, object, NJS_OBJECT_STRING);
+        njs_set_object_value(&vm->retval, object);
 
     } else {
         vm->retval = *value;
@@ -681,7 +681,7 @@ njs_string_instance_length(njs_vm_t *vm, njs_object_prop_t *prop,
         proto = njs_object(value);
 
         do {
-            if (njs_fast_path(proto->type == NJS_OBJECT_STRING)) {
+            if (njs_fast_path(proto->type == NJS_OBJECT_VALUE)) {
                 break;
             }
 
@@ -816,7 +816,7 @@ njs_string_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     if (value->type != NJS_STRING) {
 
-        if (value->type == NJS_OBJECT_STRING) {
+        if (njs_is_object_string(value)) {
             value = njs_object_value(value);
 
         } else {
@@ -1623,19 +1623,18 @@ njs_string_bytes_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     value = njs_arg(args, nargs, 1);
 
-    switch (value->type) {
-    case NJS_OBJECT_STRING:
-        value = njs_object_value(value);
-
-        /* Fall through. */
-
-    case NJS_STRING:
+    if (njs_is_string(value)) {
         return njs_string_bytes_from_string(vm, value, njs_arg(args, nargs, 2));
 
-    default:
-        if (njs_is_object(value)) {
-            return njs_string_bytes_from_array_like(vm, value);
+    } else if (njs_is_object(value)) {
+
+        if (njs_is_object_string(value)) {
+            value = njs_object_value(value);
+            return njs_string_bytes_from_string(vm, value,
+                                                njs_arg(args, nargs, 2));
         }
+
+        return njs_string_bytes_from_array_like(vm, value);
     }
 
     njs_type_error(vm, "value must be a string or array-like object");
@@ -4736,6 +4735,6 @@ const njs_object_type_init_t  njs_string_type_init = {
     .prototype_props = &njs_string_prototype_init,
     .prototype_value = { .object_value = {
                             .value = njs_string(""),
-                            .object = { .type = NJS_OBJECT_STRING } }
+                            .object = { .type = NJS_OBJECT_VALUE } }
                        },
 };
index db262e791728b29a13d03c3f96e39eab69598446..fc352b88d6b70278af452cc46f653c0ab051f345 100644 (file)
@@ -312,7 +312,7 @@ njs_symbol_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     if (value->type != NJS_SYMBOL) {
 
-        if (value->type == NJS_OBJECT_SYMBOL) {
+        if (njs_is_object_symbol(value)) {
             value = njs_object_value(value);
 
         } else {
index f879d959e8e20d9b41099bd72100a01492fb1885..3f4783c709ca9bb5be54fa23bad43ae78b286130 100644 (file)
@@ -350,18 +350,6 @@ njs_type_string(njs_value_type_t type)
     case NJS_TYPED_ARRAY:
         return "typed array";
 
-    case NJS_OBJECT_BOOLEAN:
-        return "object boolean";
-
-    case NJS_OBJECT_NUMBER:
-        return "object number";
-
-    case NJS_OBJECT_SYMBOL:
-        return "object symbol";
-
-    case NJS_OBJECT_STRING:
-        return "object string";
-
     case NJS_FUNCTION:
         return "function";
 
@@ -584,10 +572,6 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value,
     case NJS_ARRAY_BUFFER:
     case NJS_DATA_VIEW:
     case NJS_TYPED_ARRAY:
-    case NJS_OBJECT_BOOLEAN:
-    case NJS_OBJECT_NUMBER:
-    case NJS_OBJECT_SYMBOL:
-    case NJS_OBJECT_STRING:
     case NJS_REGEXP:
     case NJS_DATE:
     case NJS_PROMISE:
@@ -697,7 +681,12 @@ njs_object_property_query(njs_vm_t *vm, njs_property_query_t *pq,
 
                 break;
 
-            case NJS_OBJECT_STRING:
+            case NJS_OBJECT_VALUE:
+                ov = (njs_object_value_t *) proto;
+                if (!njs_is_string(&ov->value)) {
+                    break;
+                }
+
                 num = njs_key_to_index(key);
                 if (njs_fast_path(njs_key_is_integer_index(num, key))) {
                     ov = (njs_object_value_t *) proto;
@@ -707,6 +696,8 @@ njs_object_property_query(njs_vm_t *vm, njs_property_query_t *pq,
                     }
                 }
 
+                break;
+
             default:
                 break;
             }
@@ -1497,7 +1488,8 @@ njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
 njs_int_t
 njs_value_to_object(njs_vm_t *vm, njs_value_t *value)
 {
-    njs_object_t  *object;
+    njs_uint_t          index;
+    njs_object_value_t  *object;
 
     if (njs_slow_path(njs_is_null_or_undefined(value))) {
         njs_type_error(vm, "cannot convert null or undefined to object");
@@ -1509,12 +1501,13 @@ njs_value_to_object(njs_vm_t *vm, njs_value_t *value)
     }
 
     if (njs_is_primitive(value)) {
-        object = njs_object_value_alloc(vm, value, value->type);
+        index = njs_primitive_prototype_index(value->type);
+        object = njs_object_value_alloc(vm, index, 0, value);
         if (njs_slow_path(object == NULL)) {
             return NJS_ERROR;
         }
 
-        njs_set_type_object(value, object, njs_object_value_type(value->type));
+        njs_set_object_value(value, object);
 
         return NJS_OK;
     }
index 71eb523322f585cc3a33cb3af68098ea7e27e1c3..70d0e6704f5f8183f7dd4fa2f48063719fd050bb 100644 (file)
@@ -48,21 +48,8 @@ typedef enum {
      */
     NJS_INVALID,
 
-    /*
-     * The object types are >= NJS_OBJECT, this is used in njs_is_object().
-     * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be
-     * in the same order as NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING.  It is
-     * used in njs_primitive_prototype_index().  The order of object types
-     * is used in vm->prototypes and vm->constructors arrays.
-     */
     NJS_OBJECT                = 0x10,
     NJS_ARRAY,
-#define NJS_OBJECT_WRAPPER_MIN  (NJS_OBJECT_BOOLEAN)
-    NJS_OBJECT_BOOLEAN,
-    NJS_OBJECT_NUMBER,
-    NJS_OBJECT_SYMBOL,
-    NJS_OBJECT_STRING,
-#define NJS_OBJECT_WRAPPER_MAX  (NJS_OBJECT_STRING + 1)
 #define NJS_OBJECT_SPECIAL_MIN  (NJS_FUNCTION)
     NJS_FUNCTION,
     NJS_REGEXP,
@@ -618,17 +605,34 @@ typedef struct {
     ((value)->type == NJS_OBJECT_VALUE)
 
 
-#define njs_is_object_data(_value, tag)                                       \
+#define njs_is_object_boolean(_value)                                         \
     (((_value)->type == NJS_OBJECT_VALUE)                                     \
-     && njs_is_data(njs_object_value(_value), tag))
+     && njs_is_boolean(njs_object_value(_value)))
 
 
-#define njs_is_object_string(value)                                           \
-    ((value)->type == NJS_OBJECT_STRING)
+#define njs_is_object_number(_value)                                          \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_number(njs_object_value(_value)))
 
 
-#define njs_object_value_type(type)                                           \
-    (type + NJS_OBJECT)
+#define njs_is_object_symbol(_value)                                          \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_symbol(njs_object_value(_value)))
+
+
+#define njs_is_object_string(_value)                                          \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_string(njs_object_value(_value)))
+
+
+#define njs_is_object_primitive(_value)                                       \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_primitive(njs_object_value(_value)))
+
+
+#define njs_is_object_data(_value, tag)                                       \
+    (((_value)->type == NJS_OBJECT_VALUE)                                     \
+     && njs_is_data(njs_object_value(_value), tag))
 
 
 #define njs_is_array(value)                                                   \
index e85ae30b5255bed3457ea903ec5d21f67e120242..79163b7ddf6b3716625d9b83973184915e6fc038 100644 (file)
@@ -181,7 +181,7 @@ njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
     njs_value_t  primitive;
 
     if (njs_slow_path(!njs_is_primitive(value))) {
-        if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
+        if (njs_slow_path(njs_is_object_symbol(value))) {
             /* should fail */
             value = njs_object_value(value);
 
@@ -209,7 +209,7 @@ njs_value_to_chain(njs_vm_t *vm, njs_chb_t *chain, njs_value_t *value)
     njs_value_t  primitive;
 
     if (njs_slow_path(!njs_is_primitive(value))) {
-        if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
+        if (njs_slow_path(njs_is_object_symbol(value))) {
             /* should fail */
             value = njs_object_value(value);
 
index e19a5995555c12ed51eace5daff806c0ea3ed3c6..6f7639dd07c5a1564fa91635cc8e7fc53487fb6f 100644 (file)
@@ -1507,10 +1507,6 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
         &njs_string_undefined,
         &njs_string_undefined,
 
-        &njs_string_object,
-        &njs_string_object,
-        &njs_string_object,
-        &njs_string_object,
         &njs_string_object,
         &njs_string_object,
         &njs_string_function,
index 1cfa7699d8674c58731f883eb8d37d780e96fca4..13b334ea1c5d37c10d504940718fb906717f21a4 100644 (file)
@@ -12876,7 +12876,7 @@ static njs_unit_test_t  njs_test[] =
       njs_str("β") },
 
     { njs_str("var s = new String('αβ'); s[1] = 'b'"),
-      njs_str("TypeError: Cannot assign to read-only property \"1\" of object string") },
+      njs_str("TypeError: Cannot assign to read-only property \"1\" of object") },
 
     { njs_str("var o = Object.create(new String('αβ')); o[1] = 'a'"),
       njs_str("TypeError: Cannot assign to read-only property \"1\" of object") },
@@ -17152,6 +17152,11 @@ static njs_unit_test_t  njs_test[] =
               "JSON.stringify(a)"),
       njs_str("[null,null,\"a\"]") },
 
+    { njs_str(njs_declare_sparse_array("a", 8)
+              "a[1] = 'a'; a[2] = 'b'; a.length = 3;"
+              "JSON.stringify({a:1,b:2,c:3}, a)"),
+      njs_str("{\"a\":1,\"b\":2}") },
+
     { njs_str("var a = [1,2,3];"
               "Object.defineProperty(a, '1', {enumerable:false});"
               "JSON.stringify(a)"),