nxt_noinline njs_array_t * njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare) { uint32_t size; njs_array_t *array; array = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_array_t)); if (nxt_slow_path(array == NULL)) { return NULL; } size = length + spare; array->data = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), size * sizeof(njs_value_t)); if (nxt_slow_path(array->data == NULL)) { return NULL; } array->start = array->data; nxt_lvlhsh_init(&array->object.hash); nxt_lvlhsh_init(&array->object.shared_hash); array->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_ARRAY]; array->size = size; array->length = length; return array; }
static njs_token_t njs_parser_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { njs_token_t next; njs_parser_node_t *node; njs_vmcode_operation_t operation; switch (token) { case NJS_TOKEN_INCREMENT: operation = njs_vmcode_increment; break; case NJS_TOKEN_DECREMENT: operation = njs_vmcode_decrement; break; default: return njs_parser_post_inc_dec_expression(vm, parser, token); } next = njs_parser_token(parser); if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) { return next; } next = njs_parser_call_expression(vm, parser, next); if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) { return next; } if (parser->node->lvalue == NJS_LVALUE_NONE) { nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); return NJS_TOKEN_ILLEGAL; } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = token; node->u.operation = operation; node->left = parser->node; parser->node = node; parser->code_size += (parser->node->token == NJS_TOKEN_NAME) ? sizeof(njs_vmcode_3addr_t): sizeof(njs_vmcode_prop_get_t) + sizeof(njs_vmcode_3addr_t) + sizeof(njs_vmcode_prop_set_t); return next; }
njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) { u_char *p; njs_lexer_t *lexer; njs_regexp_flags_t flags; njs_regexp_pattern_t *pattern; lexer = parser->lexer; for (p = lexer->start; p < lexer->end; p++) { if (*p == '\\') { p++; continue; } if (*p == '/') { lexer->text.start = lexer->start; lexer->text.length = p - lexer->text.start; p++; lexer->start = p; flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "SyntaxError: Invalid RegExp flags \"%.*s\"", p - lexer->start, lexer->start); return NJS_TOKEN_ILLEGAL; } lexer->start = p; pattern = njs_regexp_pattern_create(vm, lexer->text.start, lexer->text.length, flags); if (nxt_slow_path(pattern == NULL)) { return NJS_TOKEN_ILLEGAL; } value->data.u.data = pattern; return NJS_TOKEN_REGEXP; } } nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "SyntaxError: Unterminated RegExp \"%.*s\"", p - lexer->start - 1, lexer->start - 1); return NJS_TOKEN_ILLEGAL; }
static njs_token_t njs_parser_property_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { njs_token_t next; njs_parser_node_t *node; for ( ;; ) { if (token != NJS_TOKEN_DOT && token != NJS_TOKEN_OPEN_BRACKET) { return token; } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_PROPERTY; node->lvalue = NJS_LVALUE_ENABLED; node->u.operation = njs_vmcode_property_get; node->left = parser->node; next = njs_parser_token(parser); if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) { return next; } if (token == NJS_TOKEN_DOT) { if (next != NJS_TOKEN_NAME) { return NJS_TOKEN_ILLEGAL; } token = njs_parser_property_name(vm, parser, next); } else { token = njs_parser_property_brackets(vm, parser, next); } if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } node->right = parser->node; parser->node = node; parser->code_size += sizeof(njs_vmcode_prop_get_t); } }
njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) { u_char *p; njs_lexer_t *lexer; njs_regexp_flags_t flags; njs_regexp_pattern_t *pattern; lexer = parser->lexer; for (p = lexer->start; p < lexer->end; p++) { if (*p == '\\') { p++; continue; } if (*p == '/') { lexer->text.data = lexer->start; lexer->text.len = p - lexer->text.data; p++; lexer->start = p; flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { lexer->text.data = lexer->start; lexer->text.len = p - lexer->text.data; return njs_parser_error(vm, parser, NJS_PARSER_ERROR_REGEXP_FLAGS); } lexer->start = p; pattern = njs_regexp_pattern_create(vm, lexer->text.data, lexer->text.len, flags); if (nxt_slow_path(pattern == NULL)) { return NJS_TOKEN_ILLEGAL; } value->data.u.data = pattern; return NJS_TOKEN_REGEXP; } } lexer->text.data = lexer->start - 1; lexer->text.len = p - lexer->text.data; return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP); }
njs_token_t njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *parent) { njs_token_t token; njs_index_t index; njs_parser_node_t *node; index = NJS_SCOPE_CALLEE_ARGUMENTS; do { token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (token == NJS_TOKEN_CLOSE_PARENTHESIS) { break; } token = njs_parser_assignment_expression(vm, parser, NULL, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_ARGUMENT; node->index = index; index += sizeof(njs_value_t); node->left = parser->node; parser->node->dest = node; parent->right = node; parent = node; parser->code_size += sizeof(njs_vmcode_move_t); } while (token == NJS_TOKEN_COMMA); if (nxt_slow_path(token != NJS_TOKEN_CLOSE_PARENTHESIS)) { return NJS_TOKEN_ILLEGAL; } return token; }
static njs_token_t njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { token = njs_parser_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (nxt_slow_path(token != NJS_TOKEN_CLOSE_BRACKET)) { return NJS_TOKEN_ERROR; } return njs_parser_token(parser); }
njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { njs_string_prop_t string; njs_regexp_flags_t flags; flags = 0; switch (nargs) { case 1: string.start = NULL; string.size = 0; break; default: (void) njs_string_prop(&string, &args[2]); flags = njs_regexp_flags(&string.start, string.start + string.size, 1); if (nxt_slow_path(flags < 0)) { return NXT_ERROR; } /* Fall through. */ case 2: (void) njs_string_prop(&string, &args[1]); break; } return njs_regexp_create(vm, &vm->retval, string.start, string.size, flags); }
static nxt_int_t njs_parser_statement_semicolon(njs_vm_t *vm, njs_parser_t *parser, void *data) { njs_token_t token; njs_parser_node_t *node; node = data; switch (parser->lexer->token) { case NJS_TOKEN_SEMICOLON: token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { /* TODO: NJS_TOKEN_AGAIN */ return NXT_ERROR; } /* Fall through. */ case NJS_TOKEN_END: node->right = parser->node; parser->node = node; return NXT_OK; default: break; } return NXT_ERROR; }
njs_token_t njs_parser_token(njs_parser_t *parser) { njs_token_t token; do { token = njs_lexer_token(parser->lexer); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } } while (nxt_slow_path(token == NJS_TOKEN_LINE_END)); return token; }
njs_ret_t njs_regexp_init(njs_vm_t *vm) { vm->regex_context = nxt_regex_context_create(njs_regexp_malloc, njs_regexp_free, vm->mem_cache_pool); if (nxt_slow_path(vm->regex_context == NULL)) { return NXT_ERROR; } vm->single_match_data = nxt_regex_match_data(NULL, vm->regex_context); if (nxt_slow_path(vm->single_match_data == NULL)) { return NXT_ERROR; } return NXT_OK; }
static njs_ret_t njs_array_prototype_push(njs_vm_t *vm, njs_param_t *param) { uintptr_t i, nargs; njs_ret_t ret; njs_value_t *args; njs_array_t *array; if (njs_is_array(param->object)) { array = param->object->data.u.array; nargs = param->nargs; if (nargs != 0) { if (nargs > array->size - array->length) { ret = njs_array_realloc(vm, array, 0, array->size + nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } } args = param->args; for (i = 0; i < nargs; i++) { /* GC: njs_retain(&args[i]); */ array->start[array->length++] = args[i]; } } njs_number_set(&vm->retval, array->length); } return NXT_OK; }
nxt_int_t njs_regexp_create(njs_vm_t *vm, njs_value_t *value, u_char *start, size_t length, njs_regexp_flags_t flags) { njs_regexp_t *regexp; njs_regexp_pattern_t *pattern; if (length != 0) { pattern = njs_regexp_pattern_create(vm, start, length, flags); if (nxt_slow_path(pattern == NULL)) { return NXT_ERROR; } } else { pattern = vm->shared->empty_regexp_pattern; } regexp = njs_regexp_alloc(vm, pattern); if (nxt_fast_path(regexp != NULL)) { value->data.u.regexp = regexp; value->type = NJS_REGEXP; value->data.truth = 1; return NXT_OK; } return NXT_ERROR; }
static nxt_int_t njs_parser_name_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, const void *data) { nxt_uint_t level; njs_extern_t *ext; njs_variable_t *var; njs_parser_node_t *node; node = njs_parser_node_alloc(vm); if (nxt_fast_path(node != NULL)) { ext = njs_parser_external(vm, parser); if (ext != NULL) { node->token = NJS_TOKEN_EXTERNAL; node->u.value.type = NJS_EXTERNAL; node->u.value.data.truth = 1; node->index = (njs_index_t) ext; } else { node->token = token; var = njs_parser_variable(vm, parser, &level); if (nxt_slow_path(var == NULL)) { return NJS_TOKEN_ERROR; } switch (var->state) { case NJS_VARIABLE_CREATED: var->state = NJS_VARIABLE_PENDING; parser->code_size += sizeof(njs_vmcode_1addr_t); break; case NJS_VARIABLE_PENDING: var->state = NJS_VARIABLE_USED; parser->code_size += sizeof(njs_vmcode_1addr_t); break; case NJS_VARIABLE_USED: parser->code_size += sizeof(njs_vmcode_1addr_t); break; case NJS_VARIABLE_SET: case NJS_VARIABLE_DECLARED: break; } node->lvalue = NJS_LVALUE_ENABLED; node->u.variable = var; } } parser->node = node; return NXT_OK; }
static nxt_int_t njs_parser_switch(njs_vm_t *vm, njs_parser_t *parser, void *data) { nxt_int_t ret; nxt_uint_t n; njs_token_t token; njs_parser_switch_t *swtch; const njs_parser_terminal_t *term; swtch = data; token = parser->lexer->token; n = swtch->count; term = swtch->terminal; do { if (token == term->token || term->token == NJS_TOKEN_ANY) { ret = term->operation(vm, parser, token, term->data); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } ret = njs_parser_stack_push(vm, parser, term->primed); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } if (term->token != NJS_TOKEN_ANY) { token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { /* TODO: NJS_TOKEN_AGAIN */ return NXT_ERROR; } } return NXT_OK; } term++; n--; } while (n != 0); return NXT_OK; }
njs_ret_t njs_object_constructor(njs_vm_t *vm, njs_param_t *param) { nxt_uint_t type; njs_value_t *value; njs_object_t *object; type = NJS_OBJECT; if (param->nargs == 0 || njs_is_null_or_void(¶m->args[0])) { object = njs_object_alloc(vm); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; } } else { value = ¶m->args[0]; if (njs_is_object(value)) { object = value->data.u.object; } else if (njs_is_primitive(value)) { /* value->type is the same as prototype offset. */ object = njs_object_value_alloc(vm, value, value->type); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; } type = NJS_OBJECT + value->type; } else { vm->exception = &njs_exception_type_error; return NXT_ERROR; } } vm->retval.data.u.object = object; vm->retval.type = type; vm->retval.data.truth = 1; return NXT_OK; }
njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { size_t length; njs_regexp_t *regexp; njs_string_prop_t string; njs_regexp_flags_t flags; njs_regexp_pattern_t *pattern; flags = 0; switch (nargs) { default: length = njs_string_prop(&string, &args[2]); flags = njs_regexp_flags(&string.start, string.start + length, 1); if (nxt_slow_path(flags < 0)) { return NXT_ERROR; } /* Fall through. */ case 2: string.length = njs_string_prop(&string, &args[1]); if (string.length != 0) { break; } /* Fall through. */ case 1: string.start = (u_char *) "(?:)"; string.length = sizeof("(?:)") - 1; break; } pattern = njs_regexp_pattern_create(vm, string.start, string.length, flags); if (nxt_fast_path(pattern != NULL)) { regexp = njs_regexp_alloc(vm, pattern); if (nxt_fast_path(regexp != NULL)) { vm->retval.data.u.regexp = regexp; vm->retval.type = NJS_REGEXP; vm->retval.data.truth = 1; return NXT_OK; } } return NXT_ERROR; }
njs_value_t * njs_array_add(njs_vm_t *vm, njs_value_t *value, u_char *start, size_t size) { njs_ret_t ret; njs_array_t *array; if (value != NULL) { array = value->data.u.array; if (array->size == array->length) { ret = njs_array_realloc(vm, array, 0, array->size + 1); if (nxt_slow_path(ret != NXT_OK)) { return NULL; } } } else { value = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_value_t)); if (nxt_slow_path(value == NULL)) { return NULL; } array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); if (nxt_slow_path(array == NULL)) { return NULL; } value->data.u.array = array; value->type = NJS_ARRAY; value->data.truth = 1; } ret = njs_string_create(vm, &array->start[array->length++], start, size, 0); if (nxt_fast_path(ret == NXT_OK)) { return value; } return NULL; }
njs_token_t njs_parser_property_name(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { nxt_int_t ret; njs_parser_node_t *node; node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_STRING; ret = njs_parser_string_create(vm, &node->u.value); if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } parser->node = node; return njs_parser_token(parser); }
njs_ret_t njs_array_realloc(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t size) { nxt_uint_t n; njs_value_t *value; if (size != array->size) { if (size < 16) { size *= 2; } else { size += size / 2; } } value = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), (prepend + size) * sizeof(njs_value_t)); if (nxt_slow_path(value == NULL)) { return NXT_ERROR; } /* GC: old = array->data */ array->data = value; while (prepend != 0) { njs_set_invalid(value); value++; prepend--; } memcpy(value, array->start, array->size * sizeof(njs_value_t)); array->start = value; n = array->size; array->size = size; value += n; size -= n; while (size != 0) { njs_set_invalid(value); value++; size--; } /* GC: free old pointer. */ return NXT_OK; }
njs_ret_t njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value) { int32_t index; nxt_int_t ret; njs_function_t *function; njs_object_prop_t *prop; nxt_lvlhsh_query_t lhq; static const njs_value_t prototype = njs_string("prototype"); function = value->data.u.function; index = function - vm->functions; if (index < 0 && index > NJS_PROTOTYPE_MAX) { vm->retval = njs_value_void; return NXT_OK; } prop = njs_object_prop_alloc(vm, &prototype); if (nxt_slow_path(prop == NULL)) { return NXT_ERROR; } prop->value.data.u.object = &vm->prototypes[index]; prop->value.type = NJS_OBJECT; prop->value.data.truth = 1; prop->enumerable = 0; prop->writable = 0; prop->configurable = 0; lhq.value = prop; lhq.key_hash = NJS_PROTOTYPE_HASH; lhq.key.len = sizeof("prototype") - 1; lhq.key.data = (u_char *) "prototype"; lhq.replace = 0; lhq.pool = vm->mem_cache_pool; lhq.proto = &njs_object_hash_proto; ret = nxt_lvlhsh_insert(&function->object.hash, &lhq); if (nxt_fast_path(ret == NXT_OK)) { vm->retval = prop->value; } /* TODO: exception NXT_ERROR. */ return ret; }
static njs_ret_t njs_array_prototype_concat(njs_vm_t *vm, njs_param_t *param) { size_t length; uintptr_t nargs; nxt_uint_t i; njs_value_t *object, *args, *value; njs_array_t *array; object = param->object; if (njs_is_array(object)) { length = object->data.u.array->length; } else { length = 1; } nargs = param->nargs; args = param->args; for (i = 0; i < nargs; i++) { if (njs_is_array(&args[i])) { length += args[i].data.u.array->length; } else { length++; } } array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); if (nxt_slow_path(array == NULL)) { return NXT_ERROR; } vm->retval.data.u.array = array; vm->retval.type = NJS_ARRAY; vm->retval.data.truth = 1; value = njs_array_copy(array->start, object); for (i = 0; i < nargs; i++) { value = njs_array_copy(value, &args[i]); } return NXT_OK; }
static nxt_int_t njs_parser_test_token(njs_vm_t *vm, njs_parser_t *parser, void *data) { njs_token_t token; token = (njs_token_t) data; if (parser->lexer->token == token) { token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { /* TODO: NJS_TOKEN_AGAIN */ return NXT_ERROR; } return NXT_OK; } vm->exception = &njs_exception_syntax_error; return NXT_ERROR; }
njs_parser_node_t * njs_nonrecursive_parser(njs_vm_t *vm, njs_parser_t *parser) { nxt_int_t ret; njs_token_t token; njs_parser_stack_operation_t operation; if (top < 0) { njs_parser_stack_push(vm, parser, njs_parser_statement); } token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { /* TODO: NJS_TOKEN_AGAIN */ return NULL; } do { operation = (njs_parser_stack_operation_t) njs_parser_stack_pop(parser); if (operation == NULL) { if (parser->lexer->token == NJS_TOKEN_END) { return parser->node; } break; } ret = operation(vm, parser, njs_parser_stack_pop(parser)); } while (ret == NXT_OK); nxt_thread_log_error(NXT_LOG_ERR, "unexpected token"); return NULL; }
static njs_ret_t njs_object_create(njs_vm_t *vm, njs_param_t *param) { njs_value_t *args; njs_object_t *object; if (param->nargs != 0) { args = param->args; if (njs_is_object(&args[0]) || njs_is_null(&args[0])) { object = njs_object_alloc(vm); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; } if (!njs_is_null(&args[0])) { /* GC */ object->__proto__ = args[0].data.u.object; } else { object->shared_hash = vm->shared->null_proto_hash; object->__proto__ = NULL; } vm->retval.data.u.object = object; vm->retval.type = NJS_OBJECT; vm->retval.data.truth = 1; return NXT_OK; } } vm->exception = &njs_exception_type_error; return NXT_ERROR; }
static njs_ret_t njs_array_prototype_unshift(njs_vm_t *vm, njs_param_t *param) { uintptr_t nargs; njs_ret_t ret; njs_value_t *args; njs_array_t *array; if (njs_is_array(param->object)) { array = param->object->data.u.array; nargs = param->nargs; if (nargs != 0) { if ((intptr_t) nargs > (array->start - array->data)) { ret = njs_array_realloc(vm, array, nargs, array->size); if (nxt_slow_path(ret != NXT_OK)) { return ret; } } array->length += nargs; args = param->args; do { nargs--; /* GC: njs_retain(&args[nargs]); */ array->start--; array->start[0] = args[nargs]; } while (nargs != 0); } njs_number_set(&vm->retval, array->length); } return NXT_OK; }
nxt_int_t njs_object_hash_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, const njs_object_prop_t *prop, nxt_uint_t n) { nxt_int_t ret; nxt_lvlhsh_query_t lhq; lhq.replace = 0; lhq.proto = &njs_object_hash_proto; lhq.pool = vm->mem_cache_pool; do { lhq.key.len = prop->name.short_string.size; if (lhq.key.len != NJS_STRING_LONG) { lhq.key.data = (u_char *) prop->name.short_string.start; } else { lhq.key.len = prop->name.data.string_size; lhq.key.data = prop->name.data.u.string->start; } lhq.key_hash = nxt_djb_hash(lhq.key.data, lhq.key.len); lhq.value = (void *) prop; ret = nxt_lvlhsh_insert(hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } prop++; n--; } while (n != 0); return NXT_OK; }
static nxt_int_t njs_parser_string_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, const void *data) { nxt_int_t ret; njs_parser_node_t *node; node = njs_parser_node_alloc(vm); if (nxt_fast_path(node != NULL)) { node->token = token; ret = njs_parser_string_create(vm, &node->u.value); if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } parser->node = node; return NXT_OK; } return NXT_ERROR; }
static njs_ret_t njs_array_prototype_join(njs_vm_t *vm, njs_param_t *param) { u_char *p; size_t size, length; nxt_int_t ret; nxt_uint_t i, n, max; njs_array_t *array; njs_value_t *value, *values; njs_string_prop_t separator, string; if (!njs_is_array(param->object)) { goto empty; } array = param->object->data.u.array; if (array->length == 0) { goto empty; } if (param->nargs != 0) { value = ¶m->args[0]; } else { value = (njs_value_t *) &njs_string_comma; } (void) njs_string_prop(&separator, value); max = 0; for (i = 0; i < array->length; i++) { value = &array->start[i]; if (njs_is_valid(value) && !njs_is_string(value)) { max++; } } values = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_value_t) * max); if (nxt_slow_path(values == NULL)) { return NXT_ERROR; } size = separator.size * (array->length - 1); length = separator.length * (array->length - 1); n = 0; for (i = 0; i < array->length; i++) { value = &array->start[i]; if (njs_is_valid(value)) { if (!njs_is_string(value)) { ret = njs_value_to_string(vm, &values[n], value); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } value = &values[n++]; } (void) njs_string_prop(&string, value); size += string.size; length += string.length; } } p = njs_string_alloc(vm, &vm->retval, size, length); if (nxt_slow_path(p == NULL)) { return NXT_ERROR; } n = 0; for (i = 0; i < array->length; i++) { value = &array->start[i]; if (njs_is_valid(value)) { if (!njs_is_string(value)) { value = &values[n++]; } (void) njs_string_prop(&string, value); p = memcpy(p, string.start, string.size); p += string.size; } if (i < array->length - 1) { p = memcpy(p, separator.start, separator.size); p += separator.size; } } for (i = 0; i < max; i++) { njs_release(vm, &values[i]); } nxt_mem_cache_free(vm->mem_cache_pool, values); return NXT_OK; empty: vm->retval = njs_string_empty; return NXT_OK; }
static njs_ret_t njs_array_prototype_slice(njs_vm_t *vm, njs_param_t *param) { int32_t start, end, length; uint32_t n; uintptr_t nargs; njs_array_t *array; njs_value_t *object, *args, *value; start = 0; length = 0; object = param->object; if (njs_is_array(object)) { length = object->data.u.array->length; nargs = param->nargs; if (nargs != 0) { args = param->args; start = njs_value_to_number(&args[0]); if (start < 0) { start += length; if (start < 0) { start = 0; } } end = length; if (nargs > 1) { end = njs_value_to_number(&args[1]); if (end < 0) { end += length; } } length = end - start; if (length < 0) { start = 0; length = 0; } } } array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); if (nxt_slow_path(array == NULL)) { return NXT_ERROR; } vm->retval.data.u.array = array; vm->retval.type = NJS_ARRAY; vm->retval.data.truth = 1; if (length != 0) { value = object->data.u.array->start; n = 0; do { /* GC: retain long string and object in values[start]. */ array->start[n++] = value[start++]; length--; } while (length != 0); } return NXT_OK; }