[njs] Avoiding dynamic allocation in JSON methods.
Dmitry Volyntsev
xeioex at nginx.com
Tue Nov 12 12:23:08 UTC 2019
details: https://hg.nginx.org/njs/rev/6d1d0369b041
branches:
changeset: 1233:6d1d0369b041
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Nov 12 15:09:48 2019 +0300
description:
Avoiding dynamic allocation in JSON methods.
Before 540f03725df2 the parse/stringify state had to be allocated
from dynamic memory because function calls to JS functions were
asynchronous.
diffstat:
src/njs_json.c | 492 +++++++++++++++++++++++++-------------------------------
1 files changed, 216 insertions(+), 276 deletions(-)
diffs (931 lines):
diff -r fdd56914c9ca -r 6d1d0369b041 src/njs_json.c
--- a/src/njs_json.c Sun Nov 10 01:35:02 2019 +0300
+++ b/src/njs_json.c Tue Nov 12 15:09:48 2019 +0300
@@ -42,8 +42,11 @@ typedef struct {
typedef struct {
njs_value_t retval;
- njs_arr_t stack;
+ njs_uint_t depth;
njs_json_state_t *state;
+#define NJS_JSON_MAX_DEPTH 32
+ njs_json_state_t states[NJS_JSON_MAX_DEPTH];
+
njs_function_t *function;
} njs_json_parse_t;
@@ -66,11 +69,14 @@ typedef struct {
njs_mp_t *pool;
njs_chb_node_t *nodes;
njs_chb_node_t *last;
- njs_arr_t stack;
+
+ njs_uint_t depth;
njs_json_state_t *state;
+ njs_json_state_t states[NJS_JSON_MAX_DEPTH];
njs_value_t replacer;
njs_str_t space;
+ u_char space_buf[16];
} njs_json_stringify_t;
@@ -88,17 +94,15 @@ njs_inline uint32_t njs_json_unicode(con
static const u_char *njs_json_skip_space(const u_char *start,
const u_char *end);
-static njs_int_t njs_json_parse_iterator(njs_vm_t *vm, njs_json_parse_t *parse);
+static njs_int_t njs_json_parse_iterator(njs_vm_t *vm, njs_json_parse_t *parse,
+ njs_value_t *value);
static njs_int_t njs_json_parse_iterator_call(njs_vm_t *vm,
njs_json_parse_t *parse);
-static njs_json_state_t *njs_json_push_parse_state(njs_vm_t *vm,
- njs_json_parse_t *parse, njs_value_t *value);
-static njs_json_state_t *njs_json_pop_parse_state(njs_json_parse_t *parse);
static void njs_json_parse_exception(njs_json_parse_ctx_t *ctx,
const char *msg, const u_char *pos);
static njs_int_t njs_json_stringify_iterator(njs_vm_t *vm,
- njs_json_stringify_t *stringify);
+ njs_json_stringify_t *stringify, njs_value_t *value);
static njs_function_t *njs_object_to_json_function(njs_vm_t *vm,
njs_value_t *value);
static njs_int_t njs_json_stringify_to_json(njs_vm_t *vm,
@@ -108,10 +112,6 @@ static njs_int_t njs_json_stringify_repl
njs_json_stringify_t* stringify, njs_value_t *key, njs_value_t *value);
static njs_int_t njs_json_stringify_array(njs_vm_t *vm,
njs_json_stringify_t *stringify);
-static njs_json_state_t *njs_json_push_stringify_state(njs_vm_t *vm,
- njs_json_stringify_t *stringify, const njs_value_t *value);
-static njs_json_state_t *njs_json_pop_stringify_state(
- njs_json_stringify_t *stringify);
static njs_int_t njs_json_append_value(njs_json_stringify_t *stringify,
const njs_value_t *value);
@@ -120,7 +120,8 @@ static njs_int_t njs_json_append_string(
static njs_int_t njs_json_append_number(njs_json_stringify_t *stringify,
const njs_value_t *value);
-static njs_value_t *njs_json_wrap_value(njs_vm_t *vm, const njs_value_t *value);
+static njs_object_t *njs_json_wrap_value(njs_vm_t *vm, njs_value_t *wrapper,
+ const njs_value_t *value);
#define NJS_JSON_BUF_MIN_SIZE 128
@@ -147,7 +148,7 @@ njs_json_parse(njs_vm_t *vm, njs_value_t
njs_index_t unused)
{
njs_int_t ret;
- njs_value_t *text, *value, *wrapper, lvalue;
+ njs_value_t *text, value, lvalue;
const u_char *p, *end;
njs_json_parse_t *parse, json_parse;
const njs_value_t *reviver;
@@ -156,12 +157,6 @@ njs_json_parse(njs_vm_t *vm, njs_value_t
parse = &json_parse;
- value = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
- if (njs_slow_path(value == NULL)) {
- njs_memory_error(vm);
- return NJS_ERROR;
- }
-
text = njs_lvalue_arg(&lvalue, args, nargs, 1);
if (njs_slow_path(!njs_is_string(text))) {
@@ -178,7 +173,7 @@ njs_json_parse(njs_vm_t *vm, njs_value_t
ctx.vm = vm;
ctx.pool = vm->mem_pool;
- ctx.depth = 32;
+ ctx.depth = NJS_JSON_MAX_DEPTH;
ctx.start = string.start;
ctx.end = end;
@@ -188,7 +183,7 @@ njs_json_parse(njs_vm_t *vm, njs_value_t
return NJS_ERROR;
}
- p = njs_json_parse_value(&ctx, value, p);
+ p = njs_json_parse_value(&ctx, &value, p);
if (njs_slow_path(p == NULL)) {
return NJS_ERROR;
}
@@ -201,37 +196,16 @@ njs_json_parse(njs_vm_t *vm, njs_value_t
reviver = njs_arg(args, nargs, 2);
- if (njs_is_function(reviver) && njs_is_object(value)) {
- wrapper = njs_json_wrap_value(vm, value);
- if (njs_slow_path(wrapper == NULL)) {
- goto memory_error;
- }
-
+ if (njs_is_function(reviver) && njs_is_object(&value)) {
parse->function = njs_function(reviver);
-
- if (njs_arr_init(vm->mem_pool, &parse->stack, NULL, 4,
- sizeof(njs_json_state_t))
- == NULL)
- {
- goto memory_error;
- }
-
- if (njs_json_push_parse_state(vm, parse, wrapper) == NULL) {
- goto memory_error;
- }
-
- return njs_json_parse_iterator(vm, parse);
+ parse->depth = 0;
+
+ return njs_json_parse_iterator(vm, parse, &value);
}
- vm->retval = *value;
+ vm->retval = value;
return NJS_OK;
-
-memory_error:
-
- njs_memory_error(vm);
-
- return NJS_ERROR;
}
@@ -253,13 +227,14 @@ njs_json_stringify(njs_vm_t *vm, njs_val
double num;
njs_int_t i;
njs_int_t ret;
- njs_value_t *wrapper, *replacer, *space;
+ njs_value_t *replacer, *space;
njs_json_stringify_t *stringify, json_stringify;
stringify = &json_stringify;
stringify->vm = vm;
stringify->pool = vm->mem_pool;
+ stringify->depth = 0;
stringify->nodes = NULL;
stringify->last = NULL;
@@ -289,15 +264,12 @@ njs_json_stringify(njs_vm_t *vm, njs_val
} else {
num = njs_number(space);
+
if (!isnan(num) && !isinf(num) && num > 0) {
num = njs_min(num, 10);
stringify->space.length = (size_t) num;
- stringify->space.start = njs_mp_alloc(vm->mem_pool,
- (size_t) num + 1);
- if (njs_slow_path(stringify->space.start == NULL)) {
- goto memory_error;
- }
+ stringify->space.start = stringify->space_buf;
for (i = 0; i < (int) num; i++) {
stringify->space.start[i] = ' ';
@@ -306,23 +278,7 @@ njs_json_stringify(njs_vm_t *vm, njs_val
}
}
- if (njs_arr_init(vm->mem_pool, &stringify->stack, NULL, 4,
- sizeof(njs_json_state_t))
- == NULL)
- {
- goto memory_error;
- }
-
- wrapper = njs_json_wrap_value(vm, njs_arg(args, nargs, 1));
- if (njs_slow_path(wrapper == NULL)) {
- goto memory_error;
- }
-
- if (njs_json_push_stringify_state(vm, stringify, wrapper) == NULL) {
- goto memory_error;
- }
-
- return njs_json_stringify_iterator(vm, stringify);
+ return njs_json_stringify_iterator(vm, stringify, njs_arg(args, nargs, 1));
memory_error:
@@ -403,7 +359,7 @@ njs_json_parse_object(njs_json_parse_ctx
{
njs_int_t ret;
njs_object_t *object;
- njs_value_t *prop_name, *prop_value;
+ njs_value_t prop_name, prop_value;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
@@ -438,12 +394,7 @@ njs_json_parse_object(njs_json_parse_ctx
goto error_token;
}
- prop_name = njs_mp_alloc(ctx->pool, sizeof(njs_value_t));
- if (njs_slow_path(prop_name == NULL)) {
- goto memory_error;
- }
-
- p = njs_json_parse_string(ctx, prop_name, p);
+ p = njs_json_parse_string(ctx, &prop_name, p);
if (njs_slow_path(p == NULL)) {
/* The exception is set by the called function. */
return NULL;
@@ -459,23 +410,18 @@ njs_json_parse_object(njs_json_parse_ctx
goto error_end;
}
- prop_value = njs_mp_alloc(ctx->pool, sizeof(njs_value_t));
- if (njs_slow_path(prop_value == NULL)) {
- goto memory_error;
- }
-
- p = njs_json_parse_value(ctx, prop_value, p);
+ p = njs_json_parse_value(ctx, &prop_value, p);
if (njs_slow_path(p == NULL)) {
/* The exception is set by the called function. */
return NULL;
}
- prop = njs_object_prop_alloc(ctx->vm, prop_name, prop_value, 1);
+ prop = njs_object_prop_alloc(ctx->vm, &prop_name, &prop_value, 1);
if (njs_slow_path(prop == NULL)) {
goto memory_error;
}
- njs_string_get(prop_name, &lhq.key);
+ njs_string_get(&prop_name, &lhq.key);
lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
lhq.value = prop;
lhq.replace = 1;
@@ -533,8 +479,9 @@ njs_json_parse_array(njs_json_parse_ctx_
const u_char *p)
{
njs_int_t ret;
+ njs_bool_t empty;
njs_array_t *array;
- njs_value_t *element;
+ njs_value_t element;
if (njs_slow_path(--ctx->depth == 0)) {
njs_json_parse_exception(ctx, "Nested too deep", p);
@@ -546,7 +493,7 @@ njs_json_parse_array(njs_json_parse_ctx_
return NULL;
}
- element = NULL;
+ empty = 1;
for ( ;; ) {
p = njs_json_skip_space(p + 1, ctx->end);
@@ -555,7 +502,7 @@ njs_json_parse_array(njs_json_parse_ctx_
}
if (*p == ']') {
- if (njs_slow_path(element != NULL)) {
+ if (njs_slow_path(!empty)) {
njs_json_parse_exception(ctx, "Trailing comma", p - 1);
return NULL;
}
@@ -563,22 +510,18 @@ njs_json_parse_array(njs_json_parse_ctx_
break;
}
- element = njs_mp_alloc(ctx->pool, sizeof(njs_value_t));
- if (njs_slow_path(element == NULL)) {
- njs_memory_error(ctx->vm);
- return NULL;
- }
-
- p = njs_json_parse_value(ctx, element, p);
+ p = njs_json_parse_value(ctx, &element, p);
if (njs_slow_path(p == NULL)) {
return NULL;
}
- ret = njs_array_add(ctx->vm, array, element);
+ ret = njs_array_add(ctx->vm, array, &element);
if (njs_slow_path(ret != NJS_OK)) {
return NULL;
}
+ empty = 0;
+
p = njs_json_skip_space(p, ctx->end);
if (njs_slow_path(p == ctx->end)) {
goto error_end;
@@ -913,6 +856,52 @@ njs_json_skip_space(const u_char *start,
}
+static njs_json_state_t *
+njs_json_push_parse_state(njs_vm_t *vm, njs_json_parse_t *parse,
+ njs_value_t *value)
+{
+ njs_json_state_t *state;
+
+ if (njs_slow_path(parse->depth >= NJS_JSON_MAX_DEPTH)) {
+ njs_type_error(vm, "Nested too deep or a cyclic structure");
+ return NULL;
+ }
+
+ state = &parse->states[parse->depth++];
+ state->value = *value;
+ state->index = 0;
+
+ if (njs_is_array(value)) {
+ state->type = NJS_JSON_ARRAY_START;
+
+ } else {
+ state->type = NJS_JSON_OBJECT_START;
+ state->prop_value = NULL;
+ state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0);
+ if (state->keys == NULL) {
+ return NULL;
+ }
+ }
+
+ parse->state = state;
+
+ return state;
+}
+
+
+njs_inline njs_json_state_t *
+njs_json_pop_parse_state(njs_json_parse_t *parse)
+{
+ if (parse->depth > 1) {
+ parse->depth--;
+ parse->state = &parse->states[parse->depth - 1];
+ return parse->state;
+ }
+
+ return NULL;
+}
+
+
#define njs_json_is_non_empty(_value) \
(((_value)->type == NJS_OBJECT) \
&& !njs_lvlhsh_is_empty(njs_object_hash(_value))) \
@@ -920,14 +909,26 @@ njs_json_skip_space(const u_char *start,
static njs_int_t
-njs_json_parse_iterator(njs_vm_t *vm, njs_json_parse_t *parse)
+njs_json_parse_iterator(njs_vm_t *vm, njs_json_parse_t *parse,
+ njs_value_t *value)
{
njs_int_t ret;
- njs_value_t *key, *value;
+ njs_value_t *key, *retval, wrapper;
+ njs_object_t *object;
njs_json_state_t *state;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
+ object = njs_json_wrap_value(vm, &wrapper, value);
+ if (njs_slow_path(object == NULL)) {
+ goto memory_error;
+ }
+
+ state = njs_json_push_parse_state(vm, parse, &wrapper);
+ if (njs_slow_path(state == NULL)) {
+ goto memory_error;
+ }
+
start:
state = parse->state;
@@ -969,7 +970,6 @@ start:
state = njs_json_pop_parse_state(parse);
if (state == NULL) {
vm->retval = parse->retval;
-
return NJS_OK;
}
}
@@ -1014,10 +1014,10 @@ start:
case NJS_JSON_ARRAY_START:
if (state->index < njs_array_len(&state->value)) {
- value = &njs_array_start(&state->value)[state->index];
-
- if (njs_json_is_non_empty(value)) {
- state = njs_json_push_parse_state(vm, parse, value);
+ retval = &njs_array_start(&state->value)[state->index];
+
+ if (njs_json_is_non_empty(retval)) {
+ state = njs_json_push_parse_state(vm, parse, retval);
if (state == NULL) {
goto memory_error;
}
@@ -1037,8 +1037,8 @@ start:
goto start;
case NJS_JSON_ARRAY_REPLACED:
- value = &njs_array_start(&state->value)[state->index];
- *value = parse->retval;
+ retval = &njs_array_start(&state->value)[state->index];
+ *retval = parse->retval;
state->index++;
state->type = NJS_JSON_ARRAY_START;
@@ -1098,50 +1098,6 @@ njs_json_parse_iterator_call(njs_vm_t *v
}
-static njs_json_state_t *
-njs_json_push_parse_state(njs_vm_t *vm, njs_json_parse_t *parse,
- njs_value_t *value)
-{
- njs_json_state_t *state;
-
- state = njs_arr_add(&parse->stack);
- if (state != NULL) {
- state = njs_arr_last(&parse->stack);
- state->value = *value;
- state->index = 0;
-
- if (njs_is_array(value)) {
- state->type = NJS_JSON_ARRAY_START;
-
- } else {
- state->type = NJS_JSON_OBJECT_START;
- state->prop_value = NULL;
- state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0);
- if (state->keys == NULL) {
- return NULL;
- }
- }
- }
-
- parse->state = state;
-
- return state;
-}
-
-
-static njs_json_state_t *
-njs_json_pop_parse_state(njs_json_parse_t *parse)
-{
- if (parse->stack.items > 1) {
- parse->stack.items--;
- parse->state = njs_arr_last(&parse->stack);
- return parse->state;
- }
-
- return NULL;
-}
-
-
static void
njs_json_parse_exception(njs_json_parse_ctx_t *ctx, const char *msg,
const u_char *pos)
@@ -1157,6 +1113,67 @@ njs_json_parse_exception(njs_json_parse_
}
+static njs_json_state_t *
+njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify,
+ const njs_value_t *value)
+{
+ njs_json_state_t *state;
+
+ if (njs_slow_path(stringify->depth >= NJS_JSON_MAX_DEPTH)) {
+ njs_type_error(vm, "Nested too deep or a cyclic structure");
+ return NULL;
+ }
+
+ state = &stringify->states[stringify->depth++];
+ state->value = *value;
+ state->index = 0;
+ state->written = 0;
+
+ if (njs_is_array(value)) {
+ state->type = NJS_JSON_ARRAY_START;
+
+ } else {
+ state->type = NJS_JSON_OBJECT_START;
+ state->prop_value = NULL;
+
+ if (njs_is_array(&stringify->replacer)) {
+ state->keys = njs_array(&stringify->replacer);
+
+ } else {
+ if (njs_is_external(value)) {
+ state->keys = njs_extern_keys_array(vm, value->external.proto);
+
+ } else {
+ state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
+ 0);
+ }
+
+ if (njs_slow_path(state->keys == NULL)) {
+ return NULL;
+ }
+ }
+ }
+
+ stringify->state = state;
+
+ return state;
+}
+
+
+njs_inline njs_json_state_t *
+njs_json_pop_stringify_state(njs_json_stringify_t *stringify)
+{
+ if (stringify->depth > 1) {
+ stringify->depth--;
+ stringify->state = &stringify->states[stringify->depth - 1];
+ stringify->state->written = 1;
+ return stringify->state;
+ }
+
+ return NULL;
+}
+
+
#define njs_json_is_object(value) \
(((value)->type == NJS_OBJECT) \
|| ((value)->type == NJS_ARRAY) \
@@ -1183,7 +1200,7 @@ njs_json_parse_exception(njs_json_parse_
#define njs_json_stringify_append_key(key) \
if (state->written) { \
njs_json_stringify_append(",", 1); \
- njs_json_stringify_indent(stringify->stack.items); \
+ njs_json_stringify_indent(stringify->depth); \
} \
\
state->written = 1; \
@@ -1207,7 +1224,8 @@ njs_json_parse_exception(njs_json_parse_
static njs_int_t
-njs_json_stringify_iterator(njs_vm_t *vm, njs_json_stringify_t *stringify)
+njs_json_stringify_iterator(njs_vm_t *vm, njs_json_stringify_t *stringify,
+ njs_value_t *value)
{
u_char *start;
size_t size;
@@ -1215,12 +1233,23 @@ njs_json_stringify_iterator(njs_vm_t *vm
njs_int_t i;
njs_int_t ret;
njs_str_t str;
- njs_value_t *key, *value;
+ njs_value_t *key, *retval, wrapper;
+ njs_object_t *object;
njs_function_t *to_json;
njs_json_state_t *state;
njs_object_prop_t *prop, scratch;
njs_lvlhsh_query_t lhq;
+ object = njs_json_wrap_value(vm, &wrapper, value);
+ if (njs_slow_path(object == NULL)) {
+ goto memory_error;
+ }
+
+ state = njs_json_push_stringify_state(vm, stringify, &wrapper);
+ if (njs_slow_path(state == NULL)) {
+ goto memory_error;
+ }
+
start:
state = stringify->state;
@@ -1229,14 +1258,14 @@ start:
switch (state->type) {
case NJS_JSON_OBJECT_START:
njs_json_stringify_append("{", 1);
- njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_indent(stringify->depth);
state->type = NJS_JSON_OBJECT_CONTINUE;
/* Fall through. */
case NJS_JSON_OBJECT_CONTINUE:
if (state->index >= state->keys->length) {
- njs_json_stringify_indent(stringify->stack.items - 1);
+ njs_json_stringify_indent(stringify->depth - 1);
njs_json_stringify_append("}", 1);
state = njs_json_pop_stringify_state(stringify);
@@ -1352,9 +1381,9 @@ start:
njs_json_stringify_append_key(&stringify->key);
- value = &stringify->retval;
- if (njs_is_object(value)) {
- state = njs_json_push_stringify_state(vm, stringify, value);
+ retval = &stringify->retval;
+ if (njs_is_object(retval)) {
+ state = njs_json_push_stringify_state(vm, stringify, retval);
if (state == NULL) {
return NJS_ERROR;
}
@@ -1362,20 +1391,20 @@ start:
break;
}
- njs_json_stringify_append_value(value);
+ njs_json_stringify_append_value(retval);
break;
case NJS_JSON_ARRAY_START:
njs_json_stringify_append("[", 1);
- njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_indent(stringify->depth);
state->type = NJS_JSON_ARRAY_CONTINUE;
/* Fall through. */
case NJS_JSON_ARRAY_CONTINUE:
if (state->index >= njs_array_len(&state->value)) {
- njs_json_stringify_indent(stringify->stack.items - 1);
+ njs_json_stringify_indent(stringify->depth - 1);
njs_json_stringify_append("]", 1);
state = njs_json_pop_stringify_state(stringify);
@@ -1388,16 +1417,16 @@ start:
if (state->written) {
njs_json_stringify_append(",", 1);
- njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_indent(stringify->depth);
}
- value = &njs_array_start(&state->value)[state->index++];
-
- if (njs_is_object(value)) {
- to_json = njs_object_to_json_function(vm, value);
+ retval = &njs_array_start(&state->value)[state->index++];
+
+ if (njs_is_object(retval)) {
+ to_json = njs_object_to_json_function(vm, retval);
if (to_json != NULL) {
ret = njs_json_stringify_to_json(vm, stringify, to_json,
- NULL, value);
+ NULL, retval);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1407,7 +1436,7 @@ start:
}
if (njs_is_function(&stringify->replacer)) {
- ret = njs_json_stringify_replacer(vm, stringify, NULL, value);
+ ret = njs_json_stringify_replacer(vm, stringify, NULL, retval);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1415,8 +1444,8 @@ start:
goto start;
}
- if (njs_json_is_object(value)) {
- state = njs_json_push_stringify_state(vm, stringify, value);
+ if (njs_json_is_object(retval)) {
+ state = njs_json_push_stringify_state(vm, stringify, retval);
if (state == NULL) {
return NJS_ERROR;
}
@@ -1424,7 +1453,7 @@ start:
break;
}
- njs_json_stringify_append_value(value);
+ njs_json_stringify_append_value(retval);
break;
@@ -1699,73 +1728,6 @@ njs_json_stringify_array(njs_vm_t *vm, n
}
-static njs_json_state_t *
-njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify,
- const njs_value_t *value)
-{
- njs_json_state_t *state;
-
- if (stringify->stack.items >= 32) {
- njs_type_error(stringify->vm,
- "Nested too deep or a cyclic structure");
- return NULL;
- }
-
- state = njs_arr_add(&stringify->stack);
- if (njs_slow_path(state == NULL)) {
- njs_memory_error(vm);
- return NULL;
- }
-
- state = njs_arr_last(&stringify->stack);
- state->value = *value;
- state->index = 0;
- state->written = 0;
-
- if (njs_is_array(value)) {
- state->type = NJS_JSON_ARRAY_START;
-
- } else {
- state->type = NJS_JSON_OBJECT_START;
- state->prop_value = NULL;
-
- if (njs_is_array(&stringify->replacer)) {
- state->keys = njs_array(&stringify->replacer);
-
- } else {
- if (njs_is_external(value)) {
- state->keys = njs_extern_keys_array(vm, value->external.proto);
-
- } else {
- state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
- 0);
- }
-
- if (state->keys == NULL) {
- return NULL;
- }
- }
- }
-
- stringify->state = state;
- return state;
-}
-
-
-static njs_json_state_t *
-njs_json_pop_stringify_state(njs_json_stringify_t *stringify)
-{
- if (stringify->stack.items > 1) {
- stringify->stack.items--;
- stringify->state = njs_arr_last(&stringify->stack);
- stringify->state->written = 1;
- return stringify->state;
- }
-
- return NULL;
-}
-
-
static njs_int_t
njs_json_append_value(njs_json_stringify_t *stringify, const njs_value_t *value)
{
@@ -1945,19 +1907,14 @@ njs_json_append_number(njs_json_stringif
/*
* Wraps a value as '{"": <value>}'.
*/
-static njs_value_t *
-njs_json_wrap_value(njs_vm_t *vm, const njs_value_t *value)
+static njs_object_t *
+njs_json_wrap_value(njs_vm_t *vm, njs_value_t *wrapper,
+ const njs_value_t *value)
{
njs_int_t ret;
- njs_value_t *wrapper;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
- wrapper = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
- if (njs_slow_path(wrapper == NULL)) {
- return NULL;
- }
-
wrapper->data.u.object = njs_object_alloc(vm);
if (njs_slow_path(njs_object(wrapper) == NULL)) {
return NULL;
@@ -1984,7 +1941,7 @@ njs_json_wrap_value(njs_vm_t *vm, const
return NULL;
}
- return wrapper;
+ return wrapper->data.u.object;
}
@@ -2174,7 +2131,7 @@ njs_dump_value(njs_json_stringify_t *str
case NJS_STRING:
njs_string_get(value, &str);
- if (!console || stringify->stack.items != 0) {
+ if (!console || stringify->depth != 0) {
return njs_json_append_string(stringify, value, '\'');
}
@@ -2384,7 +2341,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
njs_json_state_t *state;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
- njs_json_stringify_t *stringify;
+ njs_json_stringify_t *stringify, dump_stringify;
const njs_value_t string_get = njs_string("[Getter]");
const njs_value_t string_set = njs_string("[Setter]");
@@ -2394,17 +2351,13 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
goto exception;
}
- stringify = njs_mp_alloc(vm->mem_pool, sizeof(njs_json_stringify_t));
-
- if (njs_slow_path(stringify == NULL)) {
- goto memory_error;
- }
+ stringify = &dump_stringify;
stringify->vm = vm;
stringify->pool = vm->mem_pool;
+ stringify->depth = 0;
stringify->nodes = NULL;
stringify->last = NULL;
- stringify->stack.items = 0;
njs_set_undefined(&stringify->replacer);
if (!njs_dump_is_object(value)) {
@@ -2416,39 +2369,26 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
goto done;
}
+ indent = njs_min(indent, 10);
stringify->space.length = indent;
- stringify->space.start = njs_mp_alloc(vm->mem_pool, indent);
- if (njs_slow_path(stringify->space.start == NULL)) {
- goto memory_error;
- }
+ stringify->space.start = stringify->space_buf;
njs_memset(stringify->space.start, ' ', indent);
- if (njs_arr_init(vm->mem_pool, &stringify->stack, NULL, 4,
- sizeof(njs_json_state_t))
- == NULL)
- {
- goto memory_error;
- }
-
- if (njs_json_push_stringify_state(vm, stringify, value) == NULL) {
- goto memory_error;
- }
-
- state = stringify->state;
+ state = njs_json_push_stringify_state(vm, stringify, value);
for ( ;; ) {
switch (state->type) {
case NJS_JSON_OBJECT_START:
njs_json_stringify_append("{", 1);
- njs_json_stringify_indent(stringify->stack.items + 1);
+ njs_json_stringify_indent(stringify->depth + 1);
state->type = NJS_JSON_OBJECT_CONTINUE;
/* Fall through. */
case NJS_JSON_OBJECT_CONTINUE:
if (state->index >= state->keys->length) {
- njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_indent(stringify->depth);
njs_json_stringify_append("}", 1);
state = njs_json_pop_stringify_state(stringify);
@@ -2512,7 +2452,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
if (state->written) {
njs_json_stringify_append(",", 1);
- njs_json_stringify_indent(stringify->stack.items + 1);
+ njs_json_stringify_indent(stringify->depth + 1);
}
state->written = 1;
@@ -2537,14 +2477,14 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
case NJS_JSON_ARRAY_START:
njs_json_stringify_append("[", 1);
- njs_json_stringify_indent(stringify->stack.items + 1);
+ njs_json_stringify_indent(stringify->depth + 1);
state->type = NJS_JSON_ARRAY_CONTINUE;
/* Fall through. */
case NJS_JSON_ARRAY_CONTINUE:
if (state->index >= njs_array_len(&state->value)) {
- njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_indent(stringify->depth);
njs_json_stringify_append("]", 1);
state = njs_json_pop_stringify_state(stringify);
@@ -2557,7 +2497,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
if (state->written) {
njs_json_stringify_append(",", 1);
- njs_json_stringify_indent(stringify->stack.items + 1);
+ njs_json_stringify_indent(stringify->depth + 1);
}
val = &njs_array_start(&state->value)[state->index++];
More information about the nginx-devel
mailing list