From: Dmitry Volyntsev Date: Tue, 2 Nov 2021 12:37:00 +0000 (+0000) Subject: Getting rid of special types for primitive objects. X-Git-Tag: 0.7.1~55 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=abe3b65a259009411ca0455750deaea850c24600;p=njs.git Getting rid of special types for primitive objects. 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. --- diff --git a/src/njs_array.c b/src/njs_array.c index 07b7fe48..9b4b05ee 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -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); } diff --git a/src/njs_boolean.c b/src/njs_boolean.c index 48d52d58..7b0cc5c9 100644 --- a/src/njs_boolean.c +++ b/src/njs_boolean.c @@ -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 } } }, }; diff --git a/src/njs_builtin.c b/src/njs_builtin.c index 4e48d6ab..f4868491 100644 --- a/src/njs_builtin.c +++ b/src/njs_builtin.c @@ -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; diff --git a/src/njs_iterator.c b/src/njs_iterator.c index 4faa1cde..ca2dd973 100644 --- a/src/njs_iterator.c +++ b/src/njs_iterator.c @@ -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; } diff --git a/src/njs_json.c b/src/njs_json.c index 56df4e77..90f1f517 100644 --- a/src/njs_json.c +++ b/src/njs_json.c @@ -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, ""); + 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, ""); - 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)); } diff --git a/src/njs_number.c b/src/njs_number.c index 276b95b2..68d82556 100644 --- a/src/njs_number.c +++ b/src/njs_number.c @@ -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 } } }, }; diff --git a/src/njs_object.c b/src/njs_object.c index 02ba69ae..454e7e77 100644 --- a/src/njs_object.c +++ b/src/njs_object.c @@ -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; } diff --git a/src/njs_object.h b/src/njs_object.h index 95d17aff..85d6fde7 100644 --- a/src/njs_object.h +++ b/src/njs_object.h @@ -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); diff --git a/src/njs_string.c b/src/njs_string.c index 871561bf..a3e8da67 100644 --- a/src/njs_string.c +++ b/src/njs_string.c @@ -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 } } }, }; diff --git a/src/njs_symbol.c b/src/njs_symbol.c index db262e79..fc352b88 100644 --- a/src/njs_symbol.c +++ b/src/njs_symbol.c @@ -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 { diff --git a/src/njs_value.c b/src/njs_value.c index f879d959..3f4783c7 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -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; } diff --git a/src/njs_value.h b/src/njs_value.h index 71eb5233..70d0e670 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -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) \ diff --git a/src/njs_value_conversion.h b/src/njs_value_conversion.h index e85ae30b..79163b7d 100644 --- a/src/njs_value_conversion.h +++ b/src/njs_value_conversion.h @@ -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); diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index e19a5995..6f7639dd 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -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, diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 1cfa7699..13b334ea 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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)"),