njs_vmcode_2addr_t *code2;
njs_vmcode_3addr_t *code3;
njs_vmcode_array_t *array;
+ njs_vmcode_array_init_t *array_init;
njs_vmcode_catch_t *catch;
njs_vmcode_import_t *import;
njs_vmcode_finally_t *finally;
continue;
}
+ if (operation == NJS_VMCODE_ARRAY_INIT) {
+ array_init = (njs_vmcode_array_init_t *) p;
+
+ njs_printf("%5uD | %05uz ARRAY INIT %04Xz %04Xz %uD\n",
+ line, p - start, (size_t) array_init->array,
+ (size_t) array_init->value, array_init->index);
+
+ p += sizeof(njs_vmcode_array_init_t);
+
+ continue;
+ }
+
if (operation == NJS_VMCODE_IF_TRUE_JUMP) {
cond_jump = (njs_vmcode_cond_jump_t *) p;
} njs_generator_stack_entry_t;
+typedef struct {
+ njs_parser_node_t *array;
+ uint32_t item;
+} njs_generator_array_ctx_t;
+
+
typedef struct {
njs_generator_patch_t *patch;
njs_generator_patch_t **last;
njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node);
+static njs_int_t njs_generate_array_item(njs_vm_t *vm,
+ njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_function_expression(njs_vm_t *vm,
njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_function(njs_vm_t *vm, njs_generator_t *generator,
njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node)
{
- njs_vmcode_array_t *array;
+ njs_int_t ret;
+ njs_parser_array_item_t *item;
+ njs_vmcode_array_t *array;
+ njs_generator_array_ctx_t ctx;
+
+ if (node->u.array.items == NULL) {
+ node->index = njs_generate_object_dest_index(vm, generator, node);
+
+ } else {
+ node->index = njs_generate_node_temp_index_get(vm, generator, node);
+ }
- node->index = njs_generate_object_dest_index(vm, generator, node);
if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
return NJS_ERROR;
}
njs_generate_code(generator, njs_vmcode_array_t, array,
NJS_VMCODE_ARRAY, node);
array->ctor = node->ctor;
+ array->flat = node->array_flat;
array->retval = node->index;
- array->length = node->u.length;
+ array->length = node->u.array.length;
- /* Initialize array. */
+ if (node->u.array.items == NULL) {
+ return njs_generator_stack_pop(vm, generator, NULL);
+ }
- njs_generator_next(generator, njs_generate, node->left);
+ ctx.array = node;
+ ctx.item = 0;
+ item = njs_arr_item(node->u.array.items, 0);
+
+ njs_generator_next(generator, njs_generate, item->value);
+
+ ret = njs_generator_after(vm, generator,
+ njs_queue_first(&generator->stack), node,
+ njs_generate_array_item, &ctx, sizeof(ctx));
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_generate_array_item(njs_vm_t *vm, njs_generator_t *generator,
+ njs_parser_node_t *node)
+{
+ njs_int_t ret;
+ njs_parser_array_item_t *item;
+ njs_vmcode_array_init_t *init;
+ njs_generator_array_ctx_t *ctx;
+
+ ctx = generator->context;
+ item = njs_arr_item(ctx->array->u.array.items, ctx->item);
+
+ njs_generate_code(generator, njs_vmcode_array_init_t, init,
+ NJS_VMCODE_ARRAY_INIT, item->value);
+ init->value = item->value->index;
+ init->array = ctx->array->index;
+ init->index = item->index;
+
+ ret = njs_generate_node_index_release(vm, generator, item->value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ctx->item++;
+
+ if (ctx->item == ctx->array->u.array.items->items) {
+ return njs_generator_stack_pop(vm, generator, ctx);
+ }
+
+ item = njs_arr_item(ctx->array->u.array.items, ctx->item);
+ njs_generator_next(generator, njs_generate, item->value);
return njs_generator_after(vm, generator,
njs_queue_first(&generator->stack),
- NULL, njs_generator_pop, NULL, 0);
+ node, njs_generate_array_item, ctx, 0);
}
}
array->token_line = token->line;
+ array->array_flat = 1;
template = parser->node;
njs_lexer_consume_token(parser->lexer, 1);
array->ctor = 1;
- array->u.length++;
+ array->u.array.length++;
return NJS_OK;
{
njs_parser_node_t *object;
- njs_assert(parent->token_type == NJS_TOKEN_OBJECT
- || parent->token_type == NJS_TOKEN_ARRAY);
+ njs_assert(parent->token_type == NJS_TOKEN_OBJECT);
object = njs_parser_node_new(parser, NJS_TOKEN_OBJECT_VALUE);
if (njs_slow_path(object == NULL)) {
njs_parser_array_item(njs_parser_t *parser, njs_parser_node_t *array,
njs_parser_node_t *value)
{
- njs_int_t ret;
- njs_parser_node_t *number;
+ njs_arr_t *items;
+ njs_parser_array_item_t *item;
- number = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
- if (njs_slow_path(number == NULL)) {
- return NJS_ERROR;
- }
+ items = array->u.array.items;
- njs_set_number(&number->u.value, array->u.length);
+ if (items == NULL) {
+ items = njs_arr_create(parser->vm->mem_pool, 4,
+ sizeof(njs_parser_array_item_t));
+ if (njs_slow_path(items == NULL)) {
+ return NJS_ERROR;
+ }
- number->token_line = value->token_line;
+ array->u.array.items = items;
+ }
- ret = njs_parser_object_property(parser, array, number, value, 0);
- if (njs_slow_path(ret != NJS_OK)) {
+ item = njs_arr_add(items);
+ if (njs_slow_path(item == NULL)) {
return NJS_ERROR;
}
+ item->value = value;
+ item->index = array->u.array.length;
+
array->ctor = 0;
- array->u.length++;
+ array->u.array.length++;
return NJS_OK;
}
njs_bool_t
njs_parser_has_side_effect(njs_parser_node_t *node)
{
- njs_bool_t side_effect;
+ uint32_t i;
+ njs_bool_t side_effect;
+ njs_parser_array_item_t *item;
if (node == NULL) {
return 0;
return 1;
}
+ if (node->token_type == NJS_TOKEN_ARRAY && node->u.array.items != NULL) {
+ for (i = 0; i < node->u.array.items->items; i++) {
+ item = njs_arr_item(node->u.array.items, i);
+
+ if (njs_parser_has_side_effect(item->value)) {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
side_effect = njs_parser_has_side_effect(node->left);
if (njs_fast_path(!side_effect)) {
njs_parser_traverse(njs_vm_t *vm, njs_parser_node_t *root, void *ctx,
njs_parser_traverse_cb_t cb)
{
- njs_int_t ret;
- njs_arr_t *stack;
- njs_parser_node_t *node, **ref;
+ uint32_t i;
+ njs_int_t ret;
+ njs_arr_t *stack;
+ njs_parser_node_t *node, **ref;
+ njs_parser_array_item_t *item;
if (root == NULL) {
return NJS_OK;
goto failed;
}
+ if (node->token_type == NJS_TOKEN_ARRAY
+ && node->u.array.items != NULL)
+ {
+ i = node->u.array.items->items;
+
+ while (i != 0) {
+ item = njs_arr_item(node->u.array.items, --i);
+ ref = njs_arr_add(stack);
+ if (njs_slow_path(ref == NULL)) {
+ goto failed;
+ }
+
+ *ref = item->value;
+ }
+ }
+
if (node->left != NULL) {
ref = njs_arr_add(stack);
if (njs_slow_path(ref == NULL)) {
njs_parser_serialize_tree(njs_chb_t *chain, njs_parser_node_t *node,
njs_int_t *ret, size_t indent)
{
- njs_str_t str;
+ uint32_t i;
+ njs_str_t str;
+ njs_parser_array_item_t *item;
njs_chb_append_literal(chain, "{\"name\": \"");
break;
}
+ if (node->token_type == NJS_TOKEN_ARRAY && node->u.array.items != NULL) {
+ njs_chb_append_literal(chain, ",\n");
+ njs_parser_serialize_indent(chain, indent);
+ njs_chb_append_literal(chain, " \"items\": [");
+
+ for (i = 0; i < node->u.array.items->items; i++) {
+ item = njs_arr_item(node->u.array.items, i);
+
+ if (i != 0) {
+ njs_chb_append_literal(chain, ", ");
+ }
+
+ njs_parser_serialize_tree(chain, item->value, ret, indent + 1);
+ }
+
+ njs_chb_append_literal(chain, "]");
+ }
+
if (node->left != NULL) {
njs_chb_append_literal(chain, ",\n");
njs_parser_serialize_indent(chain, indent);
};
+typedef struct {
+ njs_parser_node_t *value;
+ uint32_t index;
+} njs_parser_array_item_t;
+
+
struct njs_parser_node_s {
njs_token_type_t token_type:16;
uint8_t ctor:1;
uint8_t hoist:1;
+ uint8_t array_flat:1;
uint8_t temporary; /* 1 bit */
uint32_t token_line;
union {
- uint32_t length;
+ struct {
+ njs_arr_t *items;
+ uint32_t length;
+ } array;
njs_variable_reference_t reference;
njs_value_t value;
njs_vmcode_t operation;
static njs_jump_off_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value,
njs_value_t *key, njs_value_t *retval);
+static njs_jump_off_t njs_vmcode_array_init(njs_vm_t *vm, u_char *pc,
+ njs_value_t *array, njs_value_t *value);
static njs_jump_off_t njs_vmcode_proto_init(njs_vm_t *vm, njs_value_t *value,
njs_value_t *key, njs_value_t *retval);
static njs_jump_off_t njs_vmcode_property_in(njs_vm_t *vm,
njs_native_frame_t *previous, *native;
njs_property_next_t *next;
njs_vmcode_import_t *import;
+ njs_vmcode_array_init_t *array_init;
njs_vmcode_generic_t *vmcode;
njs_vmcode_variable_t *var;
njs_vmcode_prop_get_t *get;
NJS_GOTO_ROW(NJS_VMCODE_IF_FALSE_JUMP),
NJS_GOTO_ROW(NJS_VMCODE_IF_EQUAL_JUMP),
NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_INIT),
+ NJS_GOTO_ROW(NJS_VMCODE_ARRAY_INIT),
NJS_GOTO_ROW(NJS_VMCODE_RETURN),
NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_FRAME),
NJS_GOTO_ROW(NJS_VMCODE_METHOD_FRAME),
BREAK;
+ CASE (NJS_VMCODE_ARRAY_INIT):
+ njs_vmcode_debug_opcode();
+
+ array_init = (njs_vmcode_array_init_t *) pc;
+
+ njs_vmcode_operand(vm, array_init->array, value1);
+ njs_vmcode_operand(vm, array_init->value, value2);
+
+ ret = njs_vmcode_array_init(vm, pc, value1, value2);
+ if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+ goto error;
+ }
+
+ BREAK;
+
CASE (NJS_VMCODE_RETURN):
njs_vmcode_debug_opcode();
code = (njs_vmcode_array_t *) pc;
- array = njs_array_alloc(vm, 0, code->length, NJS_ARRAY_SPARE);
+ array = njs_array_alloc(vm, code->flat, code->length, NJS_ARRAY_SPARE);
if (njs_fast_path(array != NULL)) {
static njs_jump_off_t
-njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
+njs_vmcode_array_init(njs_vm_t *vm, u_char *pc, njs_value_t *value,
njs_value_t *init)
{
- double num;
- uint32_t index, size;
- njs_int_t ret;
- njs_array_t *array;
- njs_value_t *val, name;
- njs_object_prop_t *prop;
- njs_flathsh_query_t fhq;
+ uint32_t index, size;
+ njs_array_t *array;
+ njs_value_t *entry;
+ njs_object_prop_t *prop;
+ njs_vmcode_array_init_t *code;
- switch (value->type) {
- case NJS_ARRAY:
- num = njs_key_to_index(key);
- if (njs_slow_path(!njs_key_is_integer_index(num, key))) {
- njs_internal_error(vm,
- "invalid index while property initialization");
- return NJS_ERROR;
- }
+ code = (njs_vmcode_array_init_t *) pc;
+ index = code->index;
- index = (uint32_t) num;
- array = value->data.u.array;
+ if (njs_slow_path(!njs_is_array(value))) {
+ njs_internal_error(vm, "array initialization target is not an array");
+ return NJS_ERROR;
+ }
- if (njs_slow_path(!array->object.fast_array)) {
- prop = njs_object_property_add(vm, value, njs_number_atom(index),
- 0);
- if (njs_slow_path(prop == NULL)) {
- return NJS_ERROR;
- }
+ array = njs_array(value);
- njs_value_assign(njs_prop_value(prop), init);
- break;
- }
+ if (njs_fast_path(array->object.fast_array)) {
+ njs_assert(index < array->size);
if (index >= array->length) {
+ entry = &array->start[array->length];
size = index - array->length;
- ret = njs_array_expand(vm, array, 0, size + 1);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- val = &array->start[array->length];
-
while (size != 0) {
- njs_set_invalid(val);
- val++;
+ njs_set_invalid(entry);
+ entry++;
size--;
}
array->length = index + 1;
}
- array->start[index] = *init;
+ njs_value_assign(&array->start[index], init);
- break;
+ } else {
+ prop = njs_object_property_add(vm, value, njs_number_atom(index), 0);
+ if (njs_slow_path(prop == NULL)) {
+ return NJS_ERROR;
+ }
+ njs_value_assign(njs_prop_value(prop), init);
+ }
+
+ return sizeof(njs_vmcode_array_init_t);
+}
+
+
+static njs_jump_off_t
+njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
+ njs_value_t *init)
+{
+ njs_int_t ret;
+ njs_value_t name;
+ njs_object_prop_t *prop;
+ njs_flathsh_query_t fhq;
+
+ switch (value->type) {
case NJS_OBJECT:
if (key->type == NJS_STRING) {
if (key->atom_id == NJS_ATOM_STRING_unknown) {
NJS_VMCODE_IF_FALSE_JUMP,
NJS_VMCODE_IF_EQUAL_JUMP,
NJS_VMCODE_PROPERTY_INIT,
+ NJS_VMCODE_ARRAY_INIT,
NJS_VMCODE_RETURN,
NJS_VMCODE_FUNCTION_FRAME,
NJS_VMCODE_METHOD_FRAME,
njs_index_t retval;
uintptr_t length;
uint8_t ctor; /* 1 bit */
+ uint8_t flat; /* 1 bit */
} njs_vmcode_array_t;
} njs_vmcode_prop_set_t;
+typedef struct {
+ njs_vmcode_t code;
+ uint32_t index;
+ njs_index_t value;
+ njs_index_t array;
+} njs_vmcode_array_init_t;
+
+
typedef struct {
njs_vmcode_t code;
njs_index_t value;
{ njs_str("var n = 1, a = [ n += 1 ]; a"),
njs_str("2") },
+ { njs_str("var a = 1; a = [a, 2]"),
+ njs_str("1,2") },
+
+ { njs_str("var a; a = [(a = 1, 2)]"),
+ njs_str("2") },
+
+ { njs_str("var i = 0; [i++, i++, i++]"),
+ njs_str("0,1,2") },
+
+ { njs_str("var a = [, 1, , 2, ,];"
+ "[a.length, Object.keys(a).length, 0 in a, 4 in a]"),
+ njs_str("5,2,false,false") },
+
+ { njs_str("njs.dump([1, [2, [3, 4]], 5])"),
+ njs_str("[1,[2,[3,4]],5]") },
+
+ { njs_str("var a = 1; a += [(a = 5, 1)][0]; a"),
+ njs_str("2") },
+
{ njs_str("var a = [ 1, 2; 3 ]; a[0] + a[1] + a[2]"),
njs_str("SyntaxError: Unexpected token \";\"") },