1) opcodes are rewritten using switch table.
2) often-used opcodes are prioritized and
inlined.
3) similar opcodes are combined into unified
handlers.
4) njs_vmcode_interpreter() return NJS_OK on
success. NJS_STOP return code is removed.
static njs_code_name_t code_names[] = {
- { njs_vmcode_object, sizeof(njs_vmcode_object_t),
+ { NJS_VMCODE_OBJECT, sizeof(njs_vmcode_object_t),
nxt_string("OBJECT ") },
- { njs_vmcode_function, sizeof(njs_vmcode_function_t),
+ { NJS_VMCODE_FUNCTION, sizeof(njs_vmcode_function_t),
nxt_string("FUNCTION ") },
- { njs_vmcode_this, sizeof(njs_vmcode_this_t),
+ { NJS_VMCODE_THIS, sizeof(njs_vmcode_this_t),
nxt_string("THIS ") },
- { njs_vmcode_arguments, sizeof(njs_vmcode_arguments_t),
+ { NJS_VMCODE_ARGUMENTS, sizeof(njs_vmcode_arguments_t),
nxt_string("ARGUMENTS ") },
- { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
+ { NJS_VMCODE_REGEXP, sizeof(njs_vmcode_regexp_t),
nxt_string("REGEXP ") },
- { njs_vmcode_template_literal, sizeof(njs_vmcode_template_literal_t),
+ { NJS_VMCODE_TEMPLATE_LITERAL, sizeof(njs_vmcode_template_literal_t),
nxt_string("TEMPLATE LITERAL") },
- { njs_vmcode_object_copy, sizeof(njs_vmcode_object_copy_t),
+ { NJS_VMCODE_OBJECT_COPY, sizeof(njs_vmcode_object_copy_t),
nxt_string("OBJECT COPY ") },
- { njs_vmcode_property_get, sizeof(njs_vmcode_prop_get_t),
+ { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t),
nxt_string("PROPERTY GET ") },
- { njs_vmcode_property_init, sizeof(njs_vmcode_prop_set_t),
+ { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
nxt_string("PROPERTY INIT ") },
- { njs_vmcode_property_set, sizeof(njs_vmcode_prop_set_t),
+ { NJS_VMCODE_PROPERTY_SET, sizeof(njs_vmcode_prop_set_t),
nxt_string("PROPERTY SET ") },
- { njs_vmcode_property_in, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_PROPERTY_IN, sizeof(njs_vmcode_3addr_t),
nxt_string("PROPERTY IN ") },
- { njs_vmcode_property_delete, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_PROPERTY_DELETE, sizeof(njs_vmcode_3addr_t),
nxt_string("PROPERTY DELETE ") },
- { njs_vmcode_instance_of, sizeof(njs_vmcode_instance_of_t),
+ { NJS_VMCODE_INSTANCE_OF, sizeof(njs_vmcode_instance_of_t),
nxt_string("INSTANCE OF ") },
- { njs_vmcode_function_call, sizeof(njs_vmcode_function_call_t),
+ { NJS_VMCODE_FUNCTION_CALL, sizeof(njs_vmcode_function_call_t),
nxt_string("FUNCTION CALL ") },
- { njs_vmcode_return, sizeof(njs_vmcode_return_t),
+ { NJS_VMCODE_RETURN, sizeof(njs_vmcode_return_t),
nxt_string("RETURN ") },
- { njs_vmcode_stop, sizeof(njs_vmcode_stop_t),
+ { NJS_VMCODE_STOP, sizeof(njs_vmcode_stop_t),
nxt_string("STOP ") },
- { njs_vmcode_increment, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_INCREMENT, sizeof(njs_vmcode_3addr_t),
nxt_string("INC ") },
- { njs_vmcode_decrement, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_DECREMENT, sizeof(njs_vmcode_3addr_t),
nxt_string("DEC ") },
- { njs_vmcode_post_increment, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_POST_INCREMENT, sizeof(njs_vmcode_3addr_t),
nxt_string("POST INC ") },
- { njs_vmcode_post_decrement, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_POST_DECREMENT, sizeof(njs_vmcode_3addr_t),
nxt_string("POST DEC ") },
- { njs_vmcode_delete, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_DELETE, sizeof(njs_vmcode_2addr_t),
nxt_string("DELETE ") },
- { njs_vmcode_void, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_VOID, sizeof(njs_vmcode_2addr_t),
nxt_string("VOID ") },
- { njs_vmcode_typeof, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_TYPEOF, sizeof(njs_vmcode_2addr_t),
nxt_string("TYPEOF ") },
- { njs_vmcode_unary_plus, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_UNARY_PLUS, sizeof(njs_vmcode_2addr_t),
nxt_string("PLUS ") },
- { njs_vmcode_unary_negation, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_UNARY_NEGATION, sizeof(njs_vmcode_2addr_t),
nxt_string("NEGATION ") },
- { njs_vmcode_addition, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_ADDITION, sizeof(njs_vmcode_3addr_t),
nxt_string("ADD ") },
- { njs_vmcode_substraction, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_SUBSTRACTION, sizeof(njs_vmcode_3addr_t),
nxt_string("SUBSTRACT ") },
- { njs_vmcode_multiplication, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_MULTIPLICATION, sizeof(njs_vmcode_3addr_t),
nxt_string("MULTIPLY ") },
- { njs_vmcode_exponentiation, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_EXPONENTIATION, sizeof(njs_vmcode_3addr_t),
nxt_string("POWER ") },
- { njs_vmcode_division, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_DIVISION, sizeof(njs_vmcode_3addr_t),
nxt_string("DIVIDE ") },
- { njs_vmcode_remainder, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_REMAINDER, sizeof(njs_vmcode_3addr_t),
nxt_string("REMAINDER ") },
- { njs_vmcode_left_shift, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_LEFT_SHIFT, sizeof(njs_vmcode_3addr_t),
nxt_string("LEFT SHIFT ") },
- { njs_vmcode_right_shift, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_RIGHT_SHIFT, sizeof(njs_vmcode_3addr_t),
nxt_string("RIGHT SHIFT ") },
- { njs_vmcode_unsigned_right_shift, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_UNSIGNED_RIGHT_SHIFT, sizeof(njs_vmcode_3addr_t),
nxt_string("USGN RIGHT SHIFT") },
- { njs_vmcode_logical_not, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_LOGICAL_NOT, sizeof(njs_vmcode_2addr_t),
nxt_string("LOGICAL NOT ") },
- { njs_vmcode_bitwise_not, sizeof(njs_vmcode_2addr_t),
+ { NJS_VMCODE_BITWISE_NOT, sizeof(njs_vmcode_2addr_t),
nxt_string("BINARY NOT ") },
- { njs_vmcode_bitwise_and, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_BITWISE_AND, sizeof(njs_vmcode_3addr_t),
nxt_string("BINARY AND ") },
- { njs_vmcode_bitwise_xor, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_BITWISE_XOR, sizeof(njs_vmcode_3addr_t),
nxt_string("BINARY XOR ") },
- { njs_vmcode_bitwise_or, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_BITWISE_OR, sizeof(njs_vmcode_3addr_t),
nxt_string("BINARY OR ") },
- { njs_vmcode_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("EQUAL ") },
- { njs_vmcode_not_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_NOT_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("NOT EQUAL ") },
- { njs_vmcode_less, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_LESS, sizeof(njs_vmcode_3addr_t),
nxt_string("LESS ") },
- { njs_vmcode_less_or_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_LESS_OR_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("LESS OR EQUAL ") },
- { njs_vmcode_greater, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_GREATER, sizeof(njs_vmcode_3addr_t),
nxt_string("GREATER ") },
- { njs_vmcode_greater_or_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_GREATER_OR_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("GREATER OR EQUAL") },
- { njs_vmcode_strict_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_STRICT_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("STRICT EQUAL ") },
- { njs_vmcode_strict_not_equal, sizeof(njs_vmcode_3addr_t),
+ { NJS_VMCODE_STRICT_NOT_EQUAL, sizeof(njs_vmcode_3addr_t),
nxt_string("STRICT NOT EQUAL") },
- { njs_vmcode_move, sizeof(njs_vmcode_move_t),
+ { NJS_VMCODE_MOVE, sizeof(njs_vmcode_move_t),
nxt_string("MOVE ") },
- { njs_vmcode_throw, sizeof(njs_vmcode_throw_t),
+ { NJS_VMCODE_THROW, sizeof(njs_vmcode_throw_t),
nxt_string("THROW ") },
};
nxt_uint_t n;
njs_vm_code_t *code;
- code = vm->code->start;
- n = vm->code->items;
+ code = vm->codes->start;
+ n = vm->codes->items;
while (n != 0) {
nxt_printf("%V:%V\n", &code->file, &code->name);
while (p < end) {
operation = *(njs_vmcode_operation_t *) p;
- if (operation == njs_vmcode_array) {
+ if (operation == NJS_VMCODE_ARRAY) {
array = (njs_vmcode_array_t *) p;
nxt_printf("%05uz ARRAY %04Xz %uz%s\n",
continue;
}
- if (operation == njs_vmcode_if_true_jump) {
+ if (operation == NJS_VMCODE_IF_TRUE_JUMP) {
cond_jump = (njs_vmcode_cond_jump_t *) p;
sign = (cond_jump->offset >= 0) ? "+" : "";
continue;
}
- if (operation == njs_vmcode_if_false_jump) {
+ if (operation == NJS_VMCODE_IF_FALSE_JUMP) {
cond_jump = (njs_vmcode_cond_jump_t *) p;
sign = (cond_jump->offset >= 0) ? "+" : "";
continue;
}
- if (operation == njs_vmcode_jump) {
+ if (operation == NJS_VMCODE_JUMP) {
jump = (njs_vmcode_jump_t *) p;
sign = (jump->offset >= 0) ? "+" : "";
continue;
}
- if (operation == njs_vmcode_if_equal_jump) {
+ if (operation == NJS_VMCODE_IF_EQUAL_JUMP) {
equal = (njs_vmcode_equal_jump_t *) p;
nxt_printf("%05uz JUMP IF EQUAL %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_test_if_true) {
+ if (operation == NJS_VMCODE_TEST_IF_TRUE) {
test_jump = (njs_vmcode_test_jump_t *) p;
nxt_printf("%05uz TEST IF TRUE %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_test_if_false) {
+ if (operation == NJS_VMCODE_TEST_IF_FALSE) {
test_jump = (njs_vmcode_test_jump_t *) p;
nxt_printf("%05uz TEST IF FALSE %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_function_frame) {
+ if (operation == NJS_VMCODE_FUNCTION_FRAME) {
function = (njs_vmcode_function_frame_t *) p;
nxt_printf("%05uz FUNCTION FRAME %04Xz %uz%s\n",
continue;
}
- if (operation == njs_vmcode_method_frame) {
+ if (operation == NJS_VMCODE_METHOD_FRAME) {
method = (njs_vmcode_method_frame_t *) p;
nxt_printf("%05uz METHOD FRAME %04Xz %04Xz %uz%s\n",
continue;
}
- if (operation == njs_vmcode_property_foreach) {
+ if (operation == NJS_VMCODE_PROPERTY_FOREACH) {
prop_foreach = (njs_vmcode_prop_foreach_t *) p;
nxt_printf("%05uz PROPERTY FOREACH %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_property_next) {
+ if (operation == NJS_VMCODE_PROPERTY_NEXT) {
prop_next = (njs_vmcode_prop_next_t *) p;
nxt_printf("%05uz PROPERTY NEXT %04Xz %04Xz %04Xz %uz\n",
continue;
}
- if (operation == njs_vmcode_try_start) {
+ if (operation == NJS_VMCODE_TRY_START) {
try_start = (njs_vmcode_try_start_t *) p;
nxt_printf("%05uz TRY START %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_try_break) {
+ if (operation == NJS_VMCODE_TRY_BREAK) {
try_tramp = (njs_vmcode_try_trampoline_t *) p;
nxt_printf("%05uz TRY BREAK %04Xz %uz\n",
continue;
}
- if (operation == njs_vmcode_try_continue) {
+ if (operation == NJS_VMCODE_TRY_CONTINUE) {
try_tramp = (njs_vmcode_try_trampoline_t *) p;
nxt_printf("%05uz TRY CONTINUE %04Xz %uz\n",
continue;
}
- if (operation == njs_vmcode_try_return) {
+ if (operation == NJS_VMCODE_TRY_RETURN) {
try_return = (njs_vmcode_try_return_t *) p;
nxt_printf("%05uz TRY RETURN %04Xz %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_catch) {
+ if (operation == NJS_VMCODE_CATCH) {
catch = (njs_vmcode_catch_t *) p;
nxt_printf("%05uz CATCH %04Xz +%uz\n",
continue;
}
- if (operation == njs_vmcode_try_end) {
+ if (operation == NJS_VMCODE_TRY_END) {
try_end = (njs_vmcode_try_end_t *) p;
nxt_printf("%05uz TRY END +%uz\n",
continue;
}
- if (operation == njs_vmcode_finally) {
+ if (operation == NJS_VMCODE_FINALLY) {
finally = (njs_vmcode_finally_t *) p;
nxt_printf("%05uz TRY FINALLY %04Xz %04Xz +%uz +%uz\n",
continue;
}
- if (operation == njs_vmcode_reference_error) {
+ if (operation == NJS_VMCODE_REFERENCE_ERROR) {
nxt_printf("%05uz REFERENCE ERROR\n", p - start);
p += sizeof(njs_vmcode_reference_error_t);
frame = (njs_frame_t *) vm->top_frame;
function = frame->native.function;
- frame->return_address = vm->current;
-
lambda = function->u.lambda;
- vm->current = lambda->start;
#if (NXT_DEBUG)
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL;
}
}
+ frame->native.call = 1;
+
vm->active_frame = frame;
- return njs_vmcode_run(vm);
+ return njs_vmcode_interpreter(vm, lambda->start);
}
/* Skip the Function.call() and Function.apply() methods frames. */
uint8_t skip; /* 1 bit */
- uint8_t call; /* 1 bit */
+ uint8_t call; /* 1 bit */
};
#define njs_generate_code_jump(generator, _code, _offset) \
do { \
njs_generate_code(generator, njs_vmcode_jump_t, _code, \
- njs_vmcode_jump, 0, 0); \
+ NJS_VMCODE_JUMP, 0, 0); \
_code->offset = _offset; \
} while (0)
#define njs_generate_code_move(generator, _code, _dst, _src) \
do { \
njs_generate_code(generator, njs_vmcode_move_t, _code, \
- njs_vmcode_move, 2, 1); \
+ NJS_VMCODE_MOVE, 2, 1); \
_code->dst = _dst; \
_code->src = _src; \
} while (0)
}
njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
- njs_vmcode_object_copy, 2, 1);
+ NJS_VMCODE_OBJECT_COPY, 2, 1);
copy->retval = node->index;
copy->object = var->index;
}
njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
- njs_vmcode_object_copy, 2, 1);
+ NJS_VMCODE_OBJECT_COPY, 2, 1);
copy->retval = node->index;
copy->object = index;
}
njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- njs_vmcode_if_false_jump, 2, 0);
+ NJS_VMCODE_IF_FALSE_JUMP, 2, 0);
cond_jump->cond = node->left->index;
ret = njs_generate_node_index_release(vm, generator, node->left);
}
njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- njs_vmcode_if_false_jump, 2, 0);
+ NJS_VMCODE_IF_FALSE_JUMP, 2, 0);
cond_jump_offset = njs_code_offset(generator, cond_jump);
cond_jump->cond = node->left->index;
}
njs_generate_code(generator, njs_vmcode_equal_jump_t, equal,
- njs_vmcode_if_equal_jump, 3, 0);
+ NJS_VMCODE_IF_EQUAL_JUMP, 3, 0);
equal->offset = offsetof(njs_vmcode_equal_jump_t, offset);
equal->value1 = index;
equal->value2 = node->left->index;
}
njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- njs_vmcode_if_true_jump, 2, 0);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, 0);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;
}
njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- njs_vmcode_if_true_jump, 2, 0);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, 0);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;
}
njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- njs_vmcode_if_true_jump, 2, 0);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, 0);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;
}
njs_generate_code(generator, njs_vmcode_prop_foreach_t, prop_foreach,
- njs_vmcode_property_foreach, 2, 1);
+ NJS_VMCODE_PROPERTY_FOREACH, 2, 1);
prop_offset = njs_code_offset(generator, prop_foreach);
prop_foreach->object = foreach->right->index;
}
njs_generate_code(generator, njs_vmcode_prop_next_t, prop_next,
- njs_vmcode_property_next, 3, 0);
+ NJS_VMCODE_PROPERTY_NEXT, 3, 0);
prop_offset = njs_code_offset(generator, prop_next);
prop_next->retval = foreach->left->index;
prop_next->object = foreach->right->index;
if (nxt_fast_path(ret == NXT_OK)) {
njs_generate_code(generator, njs_vmcode_stop_t, stop,
- njs_vmcode_stop, 1, 0);
+ NJS_VMCODE_STOP, 1, 0);
index = NJS_INDEX_NONE;
node = node->right;
if (lvalue->token == NJS_TOKEN_PROPERTY_INIT) {
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- njs_vmcode_property_init, 3, 0);
+ NJS_VMCODE_PROPERTY_INIT, 3, 0);
} else {
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- njs_vmcode_property_set, 3, 0);
+ NJS_VMCODE_PROPERTY_SET, 3, 0);
}
prop_set->value = expr->index;
/* Preserve variable value if it may be changed by expression. */
njs_generate_code(generator, njs_vmcode_move_t, move,
- njs_vmcode_move, 2, 1);
+ NJS_VMCODE_MOVE, 2, 1);
move->src = lvalue->index;
index = njs_generate_temp_index_get(vm, generator, expr);
}
njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
- njs_vmcode_property_get, 3, 1);
+ NJS_VMCODE_PROPERTY_GET, 3, 1);
prop_get->value = index;
prop_get->object = object->index;
prop_get->property = property->index;
code->src2 = expr->index;
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- njs_vmcode_property_set, 3, 0);
+ NJS_VMCODE_PROPERTY_SET, 3, 0);
prop_set->value = node->index;
prop_set->object = object->index;
prop_set->property = property->index;
}
njs_generate_code(generator, njs_vmcode_object_t, object,
- njs_vmcode_object, 1, 1);
+ NJS_VMCODE_OBJECT, 1, 1);
object->retval = node->index;
/* Initialize object. */
}
njs_generate_code(generator, njs_vmcode_array_t, array,
- njs_vmcode_array, 1, 1);
+ NJS_VMCODE_ARRAY, 1, 1);
array->code.ctor = node->ctor;
array->retval = node->index;
array->length = node->u.length;
}
njs_generate_code(generator, njs_vmcode_function_t, function,
- njs_vmcode_function, 1, 1);
+ NJS_VMCODE_FUNCTION, 1, 1);
function->lambda = lambda;
node->index = njs_generate_object_dest_index(vm, generator, node);
}
njs_generate_code(generator, njs_vmcode_regexp_t, regexp,
- njs_vmcode_regexp, 1, 1);
+ NJS_VMCODE_REGEXP, 1, 1);
regexp->retval = node->index;
regexp->pattern = node->u.value.data.u.data;
}
njs_generate_code(generator, njs_vmcode_template_literal_t, code,
- njs_vmcode_template_literal, 1, 1);
+ NJS_VMCODE_TEMPLATE_LITERAL, 1, 1);
code->retval = node->left->index;
node->index = node->left->index;
if (nxt_slow_path(njs_parser_has_side_effect(right))) {
njs_generate_code(generator, njs_vmcode_move_t, move,
- njs_vmcode_move, 2, 1);
+ NJS_VMCODE_MOVE, 2, 1);
move->src = left->index;
index = njs_generate_node_temp_index_get(vm, generator, left);
}
njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
- njs_vmcode_property_get, 3, 1);
+ NJS_VMCODE_PROPERTY_GET, 3, 1);
prop_get->value = index;
prop_get->object = lvalue->left->index;
prop_get->property = lvalue->right->index;
code->src2 = index;
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- njs_vmcode_property_set, 3, 0);
+ NJS_VMCODE_PROPERTY_SET, 3, 0);
prop_set->value = index;
prop_set->object = lvalue->left->index;
prop_set->property = lvalue->right->index;
*value++ = njs_value_undefined;
}
- if (vm->code == NULL) {
- vm->code = nxt_array_create(4, sizeof(njs_vm_code_t),
+ if (vm->codes == NULL) {
+ vm->codes = nxt_array_create(4, sizeof(njs_vm_code_t),
&njs_array_mem_proto, vm->mem_pool);
- if (nxt_slow_path(vm->code == NULL)) {
+ if (nxt_slow_path(vm->codes == NULL)) {
return NXT_ERROR;
}
}
- code = nxt_array_add(vm->code, &njs_array_mem_proto, vm->mem_pool);
+ code = nxt_array_add(vm->codes, &njs_array_mem_proto, vm->mem_pool);
if (nxt_slow_path(code == NULL)) {
return NXT_ERROR;
}
if (var->this_object) {
njs_generate_code(generator, njs_vmcode_this_t, this,
- njs_vmcode_this, 1, 0);
+ NJS_VMCODE_THIS, 1, 0);
this->dst = var->index;
}
if (var->arguments_object) {
njs_generate_code(generator, njs_vmcode_arguments_t, arguments,
- njs_vmcode_arguments, 1, 0);
+ NJS_VMCODE_ARGUMENTS, 1, 0);
arguments->dst = var->index;
}
}
if (nxt_fast_path(immediate == NULL)) {
njs_generate_code(generator, njs_vmcode_return_t, code,
- njs_vmcode_return, 1, 0);
+ NJS_VMCODE_RETURN, 1, 0);
code->retval = index;
node->index = index;
}
njs_generate_code(generator, njs_vmcode_try_return_t, try_return,
- njs_vmcode_try_return, 2, 1);
+ NJS_VMCODE_TRY_RETURN, 2, 1);
try_return->retval = index;
try_return->save = top->index;
try_return->offset = offsetof(njs_vmcode_try_return_t, offset);
}
njs_generate_code(generator, njs_vmcode_function_frame_t, func,
- njs_vmcode_function_frame, 2, 0);
+ NJS_VMCODE_FUNCTION_FRAME, 2, 0);
func_offset = njs_code_offset(generator, func);
func->code.ctor = node->ctor;
func->name = name->index;
}
njs_generate_code(generator, njs_vmcode_method_frame_t, method,
- njs_vmcode_method_frame, 3, 0);
+ NJS_VMCODE_METHOD_FRAME, 3, 0);
method_offset = njs_code_offset(generator, method);
method->code.ctor = node->ctor;
method->object = prop->left->index;
node->index = retval;
njs_generate_code(generator, njs_vmcode_function_call_t, call,
- njs_vmcode_function_call, 1, 0);
+ NJS_VMCODE_FUNCTION_CALL, 1, 0);
call->retval = retval;
return nargs;
#define njs_generate_code_catch(generator, _code, _exception) \
do { \
njs_generate_code(generator, njs_vmcode_catch_t, _code, \
- njs_vmcode_catch, 2, 0); \
+ NJS_VMCODE_CATCH, 2, 0); \
_code->offset = sizeof(njs_vmcode_catch_t); \
_code->exception = _exception; \
} while (0)
#define njs_generate_code_finally(generator, _code, _retval, _exit) \
do { \
njs_generate_code(generator, njs_vmcode_finally_t, _code, \
- njs_vmcode_finally, 2, 0); \
+ NJS_VMCODE_FINALLY, 2, 0); \
_code->retval = _retval; \
_code->exit_value = _exit; \
_code->continue_offset = offsetof(njs_vmcode_finally_t, \
njs_vmcode_try_trampoline_t *try_break, *try_continue;
njs_generate_code(generator, njs_vmcode_try_start_t, try_start,
- njs_vmcode_try_start, 2, 0);
+ NJS_VMCODE_TRY_START, 2, 0);
try_offset = njs_code_offset(generator, try_start);
exception_index = njs_generate_temp_index_get(vm, generator, node);
try_cont_label = undef_label;
njs_generate_code(generator, njs_vmcode_try_end_t, try_end,
- njs_vmcode_try_end, 0, 0);
+ NJS_VMCODE_TRY_END, 0, 0);
try_end_offset = njs_code_offset(generator, try_end);
if (try_block->exit != NULL) {
njs_generate_patch_block(vm, generator, try_block->exit);
njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_break,
- njs_vmcode_try_break, 2, 0);
+ NJS_VMCODE_TRY_BREAK, 2, 0);
try_break->exit_value = exit_index;
try_break->offset = -sizeof(njs_vmcode_try_end_t);
njs_generate_patch_block(vm, generator, try_block->continuation);
njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_continue,
- njs_vmcode_try_continue, 2, 0);
+ NJS_VMCODE_TRY_CONTINUE, 2, 0);
try_continue->exit_value = exit_index;
try_continue->offset = -sizeof(njs_vmcode_try_end_t);
}
njs_generate_code(generator, njs_vmcode_try_end_t, catch_end,
- njs_vmcode_try_end, 0, 0);
+ NJS_VMCODE_TRY_END, 0, 0);
catch_end_offset = njs_code_offset(generator, catch_end);
if (catch_block->exit != NULL) {
njs_generate_patch_block(vm, generator, catch_block->exit);
njs_generate_code(generator, njs_vmcode_try_trampoline_t,
- try_break, njs_vmcode_try_break, 2, 0);
+ try_break, NJS_VMCODE_TRY_BREAK, 2, 0);
try_break->exit_value = exit_index;
catch_block->continuation);
njs_generate_code(generator, njs_vmcode_try_trampoline_t,
- try_continue, njs_vmcode_try_continue, 2, 0);
+ try_continue, NJS_VMCODE_TRY_CONTINUE, 2, 0);
try_continue->exit_value = exit_index;
if (nxt_fast_path(ret == NXT_OK)) {
njs_generate_code(generator, njs_vmcode_throw_t, throw,
- njs_vmcode_throw, 1, 0);
+ NJS_VMCODE_THROW, 1, 0);
node->index = node->right->index;
throw->retval = node->index;
module = (njs_module_t *) expr->index;
njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
- njs_vmcode_object_copy, 2, 1);
+ NJS_VMCODE_OBJECT_COPY, 2, 1);
copy->retval = index;
copy->object = module->index;
}
njs_generate_code(generator, njs_vmcode_return_t, code,
- njs_vmcode_return, 1, 0);
+ NJS_VMCODE_RETURN, 1, 0);
code->retval = obj->index;
node->index = obj->index;
}
njs_generate_code(generator, njs_vmcode_reference_error_t, ref_err,
- njs_vmcode_reference_error, 0, 0);
+ NJS_VMCODE_REFERENCE_ERROR, 0, 0);
ref_err->token_line = node->token_line;
return NJS_TOKEN_ERROR;
}
- assign->u.operation = njs_vmcode_move;
+ assign->u.operation = NJS_VMCODE_MOVE;
assign->left = name;
assign->right = expr;
njs_parser_exponential_expression,
NULL,
3, {
- { NJS_TOKEN_MULTIPLICATION, njs_vmcode_multiplication },
- { NJS_TOKEN_DIVISION, njs_vmcode_division },
- { NJS_TOKEN_REMAINDER, njs_vmcode_remainder },
+ { NJS_TOKEN_MULTIPLICATION, NJS_VMCODE_MULTIPLICATION },
+ { NJS_TOKEN_DIVISION, NJS_VMCODE_DIVISION },
+ { NJS_TOKEN_REMAINDER, NJS_VMCODE_REMAINDER },
}
};
njs_parser_binary_expression,
&njs_parser_factor_expression,
2, {
- { NJS_TOKEN_ADDITION, njs_vmcode_addition },
- { NJS_TOKEN_SUBSTRACTION, njs_vmcode_substraction },
+ { NJS_TOKEN_ADDITION, NJS_VMCODE_ADDITION },
+ { NJS_TOKEN_SUBSTRACTION, NJS_VMCODE_SUBSTRACTION },
}
};
njs_parser_binary_expression,
&njs_parser_addition_expression,
3, {
- { NJS_TOKEN_LEFT_SHIFT, njs_vmcode_left_shift },
- { NJS_TOKEN_RIGHT_SHIFT, njs_vmcode_right_shift },
- { NJS_TOKEN_UNSIGNED_RIGHT_SHIFT, njs_vmcode_unsigned_right_shift },
+ { NJS_TOKEN_LEFT_SHIFT, NJS_VMCODE_LEFT_SHIFT },
+ { NJS_TOKEN_RIGHT_SHIFT, NJS_VMCODE_RIGHT_SHIFT },
+ { NJS_TOKEN_UNSIGNED_RIGHT_SHIFT, NJS_VMCODE_UNSIGNED_RIGHT_SHIFT },
}
};
njs_parser_binary_expression,
&njs_parser_bitwise_shift_expression,
6, {
- { NJS_TOKEN_LESS, njs_vmcode_less },
- { NJS_TOKEN_LESS_OR_EQUAL, njs_vmcode_less_or_equal },
- { NJS_TOKEN_GREATER, njs_vmcode_greater },
- { NJS_TOKEN_GREATER_OR_EQUAL, njs_vmcode_greater_or_equal },
- { NJS_TOKEN_IN, njs_vmcode_property_in },
- { NJS_TOKEN_INSTANCEOF, njs_vmcode_instance_of },
+ { NJS_TOKEN_LESS, NJS_VMCODE_LESS },
+ { NJS_TOKEN_LESS_OR_EQUAL, NJS_VMCODE_LESS_OR_EQUAL },
+ { NJS_TOKEN_GREATER, NJS_VMCODE_GREATER },
+ { NJS_TOKEN_GREATER_OR_EQUAL, NJS_VMCODE_GREATER_OR_EQUAL },
+ { NJS_TOKEN_IN, NJS_VMCODE_PROPERTY_IN },
+ { NJS_TOKEN_INSTANCEOF, NJS_VMCODE_INSTANCE_OF },
}
};
njs_parser_binary_expression,
&njs_parser_relational_expression,
4, {
- { NJS_TOKEN_EQUAL, njs_vmcode_equal },
- { NJS_TOKEN_NOT_EQUAL, njs_vmcode_not_equal },
- { NJS_TOKEN_STRICT_EQUAL, njs_vmcode_strict_equal },
- { NJS_TOKEN_STRICT_NOT_EQUAL, njs_vmcode_strict_not_equal },
+ { NJS_TOKEN_EQUAL, NJS_VMCODE_EQUAL },
+ { NJS_TOKEN_NOT_EQUAL, NJS_VMCODE_NOT_EQUAL },
+ { NJS_TOKEN_STRICT_EQUAL, NJS_VMCODE_STRICT_EQUAL },
+ { NJS_TOKEN_STRICT_NOT_EQUAL, NJS_VMCODE_STRICT_NOT_EQUAL },
}
};
njs_parser_binary_expression,
&njs_parser_equality_expression,
1, {
- { NJS_TOKEN_BITWISE_AND, njs_vmcode_bitwise_and },
+ { NJS_TOKEN_BITWISE_AND, NJS_VMCODE_BITWISE_AND },
}
};
njs_parser_binary_expression,
&njs_parser_bitwise_and_expression,
1, {
- { NJS_TOKEN_BITWISE_XOR, njs_vmcode_bitwise_xor },
+ { NJS_TOKEN_BITWISE_XOR, NJS_VMCODE_BITWISE_XOR },
}
};
njs_parser_binary_expression,
&njs_parser_bitwise_xor_expression,
1, {
- { NJS_TOKEN_BITWISE_OR, njs_vmcode_bitwise_or },
+ { NJS_TOKEN_BITWISE_OR, NJS_VMCODE_BITWISE_OR },
}
};
njs_parser_binary_expression,
&njs_parser_bitwise_or_expression,
1, {
- { NJS_TOKEN_LOGICAL_AND, njs_vmcode_test_if_false },
+ { NJS_TOKEN_LOGICAL_AND, NJS_VMCODE_TEST_IF_FALSE },
}
};
njs_parser_binary_expression,
&njs_parser_logical_and_expression,
1, {
- { NJS_TOKEN_LOGICAL_OR, njs_vmcode_test_if_true },
+ { NJS_TOKEN_LOGICAL_OR, NJS_VMCODE_TEST_IF_TRUE },
}
};
njs_parser_any_expression,
NULL,
1, {
- { NJS_TOKEN_COMMA, NULL },
+ { NJS_TOKEN_COMMA, NJS_VMCODE_NOP },
}
};
case NJS_TOKEN_ASSIGNMENT:
nxt_thread_log_debug("JS: =");
- operation = njs_vmcode_move;
+ operation = NJS_VMCODE_MOVE;
break;
case NJS_TOKEN_ADDITION_ASSIGNMENT:
nxt_thread_log_debug("JS: +=");
- operation = njs_vmcode_addition;
+ operation = NJS_VMCODE_ADDITION;
break;
case NJS_TOKEN_SUBSTRACTION_ASSIGNMENT:
nxt_thread_log_debug("JS: -=");
- operation = njs_vmcode_substraction;
+ operation = NJS_VMCODE_SUBSTRACTION;
break;
case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT:
nxt_thread_log_debug("JS: *=");
- operation = njs_vmcode_multiplication;
+ operation = NJS_VMCODE_MULTIPLICATION;
break;
case NJS_TOKEN_EXPONENTIATION_ASSIGNMENT:
nxt_thread_log_debug("JS: **=");
- operation = njs_vmcode_exponentiation;
+ operation = NJS_VMCODE_EXPONENTIATION;
break;
case NJS_TOKEN_DIVISION_ASSIGNMENT:
nxt_thread_log_debug("JS: /=");
- operation = njs_vmcode_division;
+ operation = NJS_VMCODE_DIVISION;
break;
case NJS_TOKEN_REMAINDER_ASSIGNMENT:
nxt_thread_log_debug("JS: %=");
- operation = njs_vmcode_remainder;
+ operation = NJS_VMCODE_REMAINDER;
break;
case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT:
nxt_thread_log_debug("JS: <<=");
- operation = njs_vmcode_left_shift;
+ operation = NJS_VMCODE_LEFT_SHIFT;
break;
case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT:
nxt_thread_log_debug("JS: >>=");
- operation = njs_vmcode_right_shift;
+ operation = NJS_VMCODE_RIGHT_SHIFT;
break;
case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
nxt_thread_log_debug("JS: >>=");
- operation = njs_vmcode_unsigned_right_shift;
+ operation = NJS_VMCODE_UNSIGNED_RIGHT_SHIFT;
break;
case NJS_TOKEN_BITWISE_AND_ASSIGNMENT:
nxt_thread_log_debug("JS: &=");
- operation = njs_vmcode_bitwise_and;
+ operation = NJS_VMCODE_BITWISE_AND;
break;
case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT:
nxt_thread_log_debug("JS: ^=");
- operation = njs_vmcode_bitwise_xor;
+ operation = NJS_VMCODE_BITWISE_XOR;
break;
case NJS_TOKEN_BITWISE_OR_ASSIGNMENT:
nxt_thread_log_debug("JS: |=");
- operation = njs_vmcode_bitwise_or;
+ operation = NJS_VMCODE_BITWISE_OR;
break;
default:
return NJS_TOKEN_ERROR;
}
- node->u.operation = njs_vmcode_exponentiation;
+ node->u.operation = NJS_VMCODE_EXPONENTIATION;
node->left = parser->node;
node->left->dest = node;
case NJS_TOKEN_ADDITION:
token = NJS_TOKEN_UNARY_PLUS;
- operation = njs_vmcode_unary_plus;
+ operation = NJS_VMCODE_UNARY_PLUS;
break;
case NJS_TOKEN_SUBSTRACTION:
token = NJS_TOKEN_UNARY_NEGATION;
- operation = njs_vmcode_unary_negation;
+ operation = NJS_VMCODE_UNARY_NEGATION;
break;
case NJS_TOKEN_LOGICAL_NOT:
- operation = njs_vmcode_logical_not;
+ operation = NJS_VMCODE_LOGICAL_NOT;
break;
case NJS_TOKEN_BITWISE_NOT:
- operation = njs_vmcode_bitwise_not;
+ operation = NJS_VMCODE_BITWISE_NOT;
break;
case NJS_TOKEN_TYPEOF:
- operation = njs_vmcode_typeof;
+ operation = NJS_VMCODE_TYPEOF;
break;
case NJS_TOKEN_VOID:
- operation = njs_vmcode_void;
+ operation = NJS_VMCODE_VOID;
break;
case NJS_TOKEN_DELETE:
- operation = njs_vmcode_delete;
+ operation = NJS_VMCODE_DELETE;
break;
default:
case NJS_TOKEN_PROPERTY:
node->token = NJS_TOKEN_PROPERTY_DELETE;
- node->u.operation = njs_vmcode_property_delete;
+ node->u.operation = NJS_VMCODE_PROPERTY_DELETE;
return next;
switch (token) {
case NJS_TOKEN_INCREMENT:
- operation = njs_vmcode_increment;
+ operation = NJS_VMCODE_INCREMENT;
break;
case NJS_TOKEN_DECREMENT:
- operation = njs_vmcode_decrement;
+ operation = NJS_VMCODE_DECREMENT;
break;
default:
case NJS_TOKEN_INCREMENT:
token = NJS_TOKEN_POST_INCREMENT;
- operation = njs_vmcode_post_increment;
+ operation = NJS_VMCODE_POST_INCREMENT;
break;
case NJS_TOKEN_DECREMENT:
token = NJS_TOKEN_POST_DECREMENT;
- operation = njs_vmcode_post_decrement;
+ operation = NJS_VMCODE_POST_DECREMENT;
break;
default:
return NJS_TOKEN_ERROR;
}
- node->u.operation = njs_vmcode_property_get;
+ node->u.operation = NJS_VMCODE_PROPERTY_GET;
node->left = parser->node;
if (token == NJS_TOKEN_DOT) {
return NXT_ERROR;
}
- assign->u.operation = njs_vmcode_move;
+ assign->u.operation = NJS_VMCODE_MOVE;
assign->left = propref;
assign->right = value;
* Reset the code array to prevent it from being disassembled
* again in the next iteration of the accumulative mode.
*/
- vm->code = NULL;
+ vm->codes = NULL;
nxt_memzero(&generator, sizeof(njs_generator_t));
goto fail;
}
- vm->current = generator.code_start;
+ vm->start = generator.code_start;
vm->global_scope = generator.local_scope;
vm->scope_size = generator.scope_size;
nvm->options = vm->options;
- nvm->current = vm->current;
+ nvm->start = vm->start;
nvm->external = external;
return ret;
}
- ret = njs_vmcode_interpreter(vm);
-
- if (ret == NJS_STOP) {
- ret = NJS_OK;
- }
-
- return ret;
+ return njs_vmcode_interpreter(vm, vm->start);
}
#define NJS_MAX_STACK_SIZE (16 * 1024 * 1024)
-/*
- * Negative return values handled by nJSVM interpreter as special events.
- * The values must be in range from -1 to -11, because -12 is minimal jump
- * offset on 32-bit platforms.
- * -1 (NJS_ERROR/NXT_ERROR): error or exception;
- * -2 (NJS_AGAIN/NXT_AGAIN): postpone nJSVM execution;
- * -3: not used;
- * -4 (NJS_STOP/NXT_DONE): njs_vmcode_stop() has stopped execution,
- * execution has completed successfully;
- * -5 .. -11: not used.
- */
-
-#define NJS_STOP NXT_DONE
-
-/* The last return value which preempts execution. */
-#define NJS_PREEMPT (-11)
-
/*
* NJS_PROPERTY_QUERY_GET must be less to NJS_PROPERTY_QUERY_SET
nxt_array_t *paths;
- u_char *current;
+ u_char *start;
njs_value_t *scopes[NJS_SCOPES];
njs_object_t string_object;
- nxt_array_t *code; /* of njs_vm_code_t */
+ nxt_array_t *codes; /* of njs_vm_code_t */
nxt_trace_t trace;
nxt_random_t random;
njs_array_t *array;
};
+static njs_ret_t njs_vmcode_object(njs_vm_t *vm, u_char *pc);
+static njs_ret_t njs_vmcode_array(njs_vm_t *vm, u_char *pc);
+static njs_ret_t njs_vmcode_function(njs_vm_t *vm, u_char *pc);
+static njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, u_char *pc);
+static njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, u_char *pc);
+static njs_ret_t njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *inlvd1,
+ njs_value_t *inlvd2);
+static njs_ret_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *invld);
+
+static njs_ret_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *property, njs_value_t *retval);
+static njs_ret_t njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *property,
+ njs_value_t *object);
+static njs_ret_t njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *property);
+static njs_ret_t njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *invld, u_char *pc);
+static njs_ret_t njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *value, u_char *pc);
+static njs_ret_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *constructor);
+static njs_ret_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *invld);
+
+static njs_ret_t njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *method, u_char *pc);
+static njs_ret_t njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *retval);
+
+static njs_ret_t njs_vmcode_try_start(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *offset, u_char *pc);
+static njs_ret_t njs_vmcode_try_break(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *offset);
+static njs_ret_t njs_vmcode_try_continue(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *offset);
+static njs_ret_t njs_vmcode_try_end(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *offset);
+static njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *retval, u_char *pc);
+static njs_ret_t njs_vmcode_reference_error(njs_vm_t *vm, u_char *pc);
/*
* These functions are forbidden to inline to minimize JavaScript VM
*/
nxt_int_t
-njs_vmcode_interpreter(njs_vm_t *vm)
+njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc)
{
- u_char *catch, call;
- njs_ret_t ret;
- njs_value_t *retval, *value1, *value2;
- njs_frame_t *frame;
- njs_native_frame_t *previous;
- njs_vmcode_generic_t *vmcode;
+ u_char *catch;
+ double num, exponent;
+ int32_t i32;
+ uint32_t u32;
+ njs_ret_t ret;
+ nxt_uint_t hint;
+ nxt_bool_t valid, call;
+ njs_value_t *retval, *value1, *value2, *src, *s1, *s2;
+ njs_value_t numeric1, numeric2, primitive1, primitive2,
+ dst;
+ njs_frame_t *frame;
+ njs_vmcode_this_t *this;
+ njs_native_frame_t *previous;
+ njs_property_next_t *next;
+ njs_vmcode_generic_t *vmcode;
+ njs_vmcode_prop_get_t *get;
+ njs_vmcode_prop_set_t *set;
+ njs_vmcode_operation_t op;
+ njs_vmcode_prop_next_t *pnext;
+ njs_vmcode_test_jump_t *test_jump;
+ njs_vmcode_equal_jump_t *equal;
+ njs_vmcode_try_return_t *try_return;
+ njs_vmcode_function_frame_t *function_frame;
+
+ if (nxt_slow_path(vm->count > 128)) {
+ njs_range_error(vm, "Maximum call stack size exceeded");
+ return NXT_ERROR;
+ }
+
+ vm->count++;
-start:
+next:
for ( ;; ) {
- vmcode = (njs_vmcode_generic_t *) vm->current;
+ vmcode = (njs_vmcode_generic_t *) pc;
/*
* The first operand is passed as is in value2 to
- * njs_vmcode_jump(),
- * njs_vmcode_if_true_jump(),
- * njs_vmcode_if_false_jump(),
- * njs_vmcode_validate(),
- * njs_vmcode_function_frame(),
- * njs_vmcode_function_call(),
- * njs_vmcode_return(),
- * njs_vmcode_try_start(),
- * njs_vmcode_try_continue(),
- * njs_vmcode_try_break(),
- * njs_vmcode_try_end(),
- * njs_vmcode_catch().
- * njs_vmcode_throw().
- * njs_vmcode_stop().
+ * NJS_VMCODE_JUMP,
+ * NJS_VMCODE_IF_TRUE_JUMP,
+ * NJS_VMCODE_IF_FALSE_JUMP,
+ * NJS_VMCODE_FUNCTION_FRAME,
+ * NJS_VMCODE_FUNCTION_CALL,
+ * NJS_VMCODE_RETURN,
+ * NJS_VMCODE_TRY_START,
+ * NJS_VMCODE_TRY_CONTINUE,
+ * NJS_VMCODE_TRY_BREAK,
+ * NJS_VMCODE_TRY_END,
+ * NJS_VMCODE_CATCH,
+ * NJS_VMCODE_THROW,
+ * NJS_VMCODE_STOP.
*/
value2 = (njs_value_t *) vmcode->operand1;
value1 = NULL;
value1 = njs_vmcode_operand(vm, vmcode->operand2);
}
- ret = vmcode->code.operation(vm, value1, value2);
+ op = vmcode->code.operation;
/*
* On success an operation returns size of the bytecode,
* as a single unsigned comparision.
*/
- if (nxt_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
- break;
- }
+ if (vmcode->code.retval) {
+ if (op == NJS_VMCODE_MOVE) {
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ *retval = *value1;
- vm->current += ret;
+ pc += sizeof(njs_vmcode_move_t);
+ goto next;
+ }
+
+ if (op == NJS_VMCODE_PROPERTY_GET) {
+ get = (njs_vmcode_prop_get_t *) pc;
+ retval = njs_vmcode_operand(vm, get->value);
+
+ ret = njs_value_property(vm, value1, value2, retval);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ pc += sizeof(njs_vmcode_prop_get_t);
+ goto next;
+ }
+
+ switch (op) {
+ case NJS_VMCODE_INCREMENT:
+ case NJS_VMCODE_POST_INCREMENT:
+ case NJS_VMCODE_DECREMENT:
+ case NJS_VMCODE_POST_DECREMENT:
+ if (nxt_slow_path(!njs_is_numeric(value2))) {
+ ret = njs_value_to_numeric(vm, &numeric1, value2);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto error;
+ }
+
+ num = njs_number(&numeric1);
+
+ } else {
+ num = njs_number(value2);
+ }
+
+ njs_set_number(value1,
+ num + (1 - 2 * ((op - NJS_VMCODE_INCREMENT) >> 1)));
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+
+ if (op & 1) {
+ njs_set_number(retval, num);
+
+ } else {
+ *retval = *value1;
+ }
+
+ pc += sizeof(njs_vmcode_3addr_t);
+ goto next;
+
+ /*
+ * njs_vmcode_try_return() saves a return value to use it later by
+ * njs_vmcode_finally(), and jumps to the nearest try_break block.
+ */
+ case NJS_VMCODE_TRY_RETURN:
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ *retval = *value1;
+
+ try_return = (njs_vmcode_try_return_t *) pc;
+ pc += try_return->offset;
+ goto next;
+
+ case NJS_VMCODE_LESS:
+ case NJS_VMCODE_GREATER:
+ case NJS_VMCODE_LESS_OR_EQUAL:
+ case NJS_VMCODE_GREATER_OR_EQUAL:
+ case NJS_VMCODE_ADDITION:
+ if (nxt_slow_path(!njs_is_primitive(value1))) {
+ hint = (op == NJS_VMCODE_ADDITION) && njs_is_date(value1);
+ ret = njs_value_to_primitive(vm, &primitive1, value1, hint);
+ if (ret != NXT_OK) {
+ goto error;
+ }
+
+ value1 = &primitive1;
+ }
+
+ if (nxt_slow_path(!njs_is_primitive(value2))) {
+ hint = (op == NJS_VMCODE_ADDITION) && njs_is_date(value2);
+ ret = njs_value_to_primitive(vm, &primitive2, value2, hint);
+ if (ret != NXT_OK) {
+ goto error;
+ }
+
+ value2 = &primitive2;
+ }
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+
+ if (op == NJS_VMCODE_ADDITION) {
+ if (nxt_fast_path(njs_is_numeric(value1)
+ && njs_is_numeric(value2)))
+ {
+ njs_set_number(retval, njs_number(value1)
+ + njs_number(value2));
+ pc += sizeof(njs_vmcode_3addr_t);
+ goto next;
+ }
+
+ if (njs_is_string(value1)) {
+ s1 = value1;
+ s2 = &dst;
+ src = value2;
+
+ } else {
+ s1 = &dst;
+ s2 = value2;
+ src = value1;
+ }
+
+ ret = njs_primitive_value_to_string(vm, &dst, src);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto error;
+ }
+
+ ret = njs_string_concat(vm, s1, s2);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ *retval = vm->retval;
+
+ pc += ret;
+ goto next;
+ }
+
+ if ((uint8_t) (op - NJS_VMCODE_GREATER) < 2) {
+ /* NJS_VMCODE_GREATER, NJS_VMCODE_LESS_OR_EQUAL */
+ src = value1;
+ value1 = value2;
+ value2 = src;
+ }
+
+ ret = njs_primitive_values_compare(vm, value1, value2);
+
+ if (op < NJS_VMCODE_LESS_OR_EQUAL) {
+ ret = ret > 0;
+
+ } else {
+ ret = ret == 0;
+ }
+
+ njs_set_boolean(retval, ret);
+
+ pc += sizeof(njs_vmcode_3addr_t);
+ goto next;
+
+ case NJS_VMCODE_EQUAL:
+ case NJS_VMCODE_NOT_EQUAL:
+ ret = njs_values_equal(vm, value1, value2);
+ if (nxt_slow_path(ret < 0)) {
+ goto error;
+ }
+
+ ret ^= op - NJS_VMCODE_EQUAL;
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ njs_set_boolean(retval, ret);
+
+ pc += sizeof(njs_vmcode_3addr_t);
+ goto next;
+
+ case NJS_VMCODE_SUBSTRACTION:
+ case NJS_VMCODE_MULTIPLICATION:
+ case NJS_VMCODE_EXPONENTIATION:
+ case NJS_VMCODE_DIVISION:
+ case NJS_VMCODE_REMAINDER:
+ case NJS_VMCODE_BITWISE_AND:
+ case NJS_VMCODE_BITWISE_OR:
+ case NJS_VMCODE_BITWISE_XOR:
+ case NJS_VMCODE_LEFT_SHIFT:
+ case NJS_VMCODE_RIGHT_SHIFT:
+ case NJS_VMCODE_UNSIGNED_RIGHT_SHIFT:
+ if (nxt_slow_path(!njs_is_numeric(value1))) {
+ ret = njs_value_to_numeric(vm, &numeric1, value1);
+ if (ret != NXT_OK) {
+ goto error;
+ }
+
+ value1 = &numeric1;
+ }
+
+ if (nxt_slow_path(!njs_is_numeric(value2))) {
+ ret = njs_value_to_numeric(vm, &numeric2, value2);
+ if (ret != NXT_OK) {
+ goto error;
+ }
+
+ value2 = &numeric2;
+ }
+
+ num = njs_number(value1);
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ pc += sizeof(njs_vmcode_3addr_t);
+
+ switch (op) {
+ case NJS_VMCODE_SUBSTRACTION:
+ num -= njs_number(value2);
+ break;
+
+ case NJS_VMCODE_MULTIPLICATION:
+ num *= njs_number(value2);
+ break;
+
+ case NJS_VMCODE_EXPONENTIATION:
+ exponent = njs_number(value2);
+
+ /*
+ * According to ES7:
+ * 1. If exponent is NaN, the result should be NaN;
+ * 2. The result of +/-1 ** +/-Infinity should be NaN.
+ */
+ valid = nxt_expect(1, fabs(num) != 1
+ || (!isnan(exponent)
+ && !isinf(exponent)));
+
+ if (valid) {
+ num = pow(num, exponent);
+
+ } else {
+ num = NAN;
+ }
+
+ break;
+
+ case NJS_VMCODE_DIVISION:
+ num /= njs_number(value2);
+ break;
+
+ case NJS_VMCODE_REMAINDER:
+ num = fmod(num, njs_number(value2));
+ break;
+
+ case NJS_VMCODE_BITWISE_AND:
+ case NJS_VMCODE_BITWISE_OR:
+ case NJS_VMCODE_BITWISE_XOR:
+ i32 = njs_number_to_int32(num);
+
+ switch (op) {
+ case NJS_VMCODE_BITWISE_AND:
+ i32 = i32 & njs_number_to_int32(njs_number(value2));
+ break;
+
+ case NJS_VMCODE_BITWISE_OR:
+ i32 = i32 | njs_number_to_int32(njs_number(value2));
+ break;
+
+ case NJS_VMCODE_BITWISE_XOR:
+ i32 = i32 ^ njs_number_to_int32(njs_number(value2));
+ break;
+ }
+
+ njs_set_int32(retval, i32);
+ goto next;
+
+ default:
+ u32 = njs_number_to_uint32(njs_number(value2));
+
+ switch (op) {
+ case NJS_VMCODE_LEFT_SHIFT:
+ case NJS_VMCODE_RIGHT_SHIFT:
+ i32 = njs_number_to_int32(num);
+
+ if (op == NJS_VMCODE_LEFT_SHIFT) {
+ i32 <<= u32 & 0x1f;
+ } else {
+ i32 >>= u32 & 0x1f;
+ }
+
+ njs_set_int32(retval, i32);
+
+ break;
+
+ default: /* NJS_VMCODE_UNSIGNED_RIGHT_SHIFT */
+ njs_set_uint32(retval,
+ njs_number_to_uint32(num)
+ >> (u32 & 0x1f));
+ }
+
+ goto next;
+ }
+
+ njs_set_number(retval, num);
+ goto next;
+
+ case NJS_VMCODE_OBJECT_COPY:
+ ret = njs_vmcode_object_copy(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_TEMPLATE_LITERAL:
+ ret = njs_vmcode_template_literal(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_PROPERTY_IN:
+ ret = njs_vmcode_property_in(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_PROPERTY_DELETE:
+ ret = njs_vmcode_property_delete(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_PROPERTY_FOREACH:
+ ret = njs_vmcode_property_foreach(vm, value1, value2, pc);
+ break;
+
+ case NJS_VMCODE_STRICT_EQUAL:
+ case NJS_VMCODE_STRICT_NOT_EQUAL:
+ ret = njs_values_strict_equal(value1, value2);
+
+ ret ^= op - NJS_VMCODE_STRICT_EQUAL;
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ njs_set_boolean(retval, ret);
+
+ pc += sizeof(njs_vmcode_3addr_t);
+ goto next;
+
+ case NJS_VMCODE_TEST_IF_TRUE:
+ case NJS_VMCODE_TEST_IF_FALSE:
+ ret = njs_is_true(value1);
+
+ ret ^= op - NJS_VMCODE_TEST_IF_TRUE;
+
+ if (ret) {
+ test_jump = (njs_vmcode_test_jump_t *) pc;
+ ret = test_jump->offset;
+
+ } else {
+ ret = sizeof(njs_vmcode_3addr_t);
+ }
+
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ *retval = *value1;
+
+ pc += ret;
+ goto next;
+
+ case NJS_VMCODE_UNARY_PLUS:
+ case NJS_VMCODE_UNARY_NEGATION:
+ case NJS_VMCODE_BITWISE_NOT:
+ if (nxt_slow_path(!njs_is_numeric(value1))) {
+ ret = njs_value_to_numeric(vm, &numeric1, value1);
+ if (ret != NXT_OK) {
+ goto error;
+ }
+
+ value1 = &numeric1;
+ }
+
+ num = njs_number(value1);
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+
+ switch (op) {
+ case NJS_VMCODE_UNARY_NEGATION:
+ num = -num;
+
+ /* Fall through. */
+ case NJS_VMCODE_UNARY_PLUS:
+ njs_set_number(retval, num);
+ break;
+
+ case NJS_VMCODE_BITWISE_NOT:
+ njs_set_int32(retval, ~njs_number_to_integer(num));
+ }
+
+ pc += sizeof(njs_vmcode_2addr_t);
+ goto next;
+
+ case NJS_VMCODE_LOGICAL_NOT:
+ retval = njs_vmcode_operand(vm, vmcode->operand1);
+ njs_set_boolean(retval, !njs_is_true(value1));
+
+ pc += sizeof(njs_vmcode_2addr_t);
+ goto next;
+
+ case NJS_VMCODE_OBJECT:
+ ret = njs_vmcode_object(vm, pc);
+ break;
+
+ case NJS_VMCODE_ARRAY:
+ ret = njs_vmcode_array(vm, pc);
+ break;
+
+ case NJS_VMCODE_FUNCTION:
+ ret = njs_vmcode_function(vm, pc);
+ break;
+
+ case NJS_VMCODE_REGEXP:
+ ret = njs_vmcode_regexp(vm, pc);
+ break;
+
+ case NJS_VMCODE_INSTANCE_OF:
+ ret = njs_vmcode_instance_of(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_TYPEOF:
+ ret = njs_vmcode_typeof(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_VOID:
+ vm->retval = njs_value_undefined;
+
+ ret = sizeof(njs_vmcode_2addr_t);
+ break;
+
+ case NJS_VMCODE_DELETE:
+ njs_release(vm, value1);
+ vm->retval = njs_value_true;
+
+ ret = sizeof(njs_vmcode_2addr_t);
+ break;
+
+ default:
+ njs_internal_error(vm, "%d has retval", op);
+ goto error;
+ }
+
+ if (nxt_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+ break;
+ }
- if (vmcode->code.retval) {
retval = njs_vmcode_operand(vm, vmcode->operand1);
njs_release(vm, retval);
*retval = vm->retval;
- }
- }
- if (ret == NXT_ERROR) {
+ } else {
+ switch (op) {
+ case NJS_VMCODE_STOP:
+ value2 = njs_vmcode_operand(vm, value2);
+ vm->retval = *value2;
- for ( ;; ) {
- frame = (njs_frame_t *) vm->top_frame;
+ ret = NJS_OK;
+ goto done;
- call = frame->native.call;
- catch = frame->native.exception.catch;
+ case NJS_VMCODE_JUMP:
+ ret = (njs_ret_t) value2;
+ break;
- if (catch != NULL) {
- vm->current = catch;
+ case NJS_VMCODE_PROPERTY_SET:
+ set = (njs_vmcode_prop_set_t *) pc;
+ retval = njs_vmcode_operand(vm, set->value);
- if (vm->debug != NULL) {
- nxt_array_reset(vm->backtrace);
+ ret = njs_value_property_set(vm, value1, value2, retval);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
}
- goto start;
- }
+ ret = sizeof(njs_vmcode_prop_set_t);
+ break;
- if (vm->debug != NULL
- && njs_vm_add_backtrace_entry(vm, frame) != NXT_OK)
- {
- return NXT_ERROR;
- }
+ case NJS_VMCODE_IF_TRUE_JUMP:
+ case NJS_VMCODE_IF_FALSE_JUMP:
+ ret = njs_is_true(value1);
- previous = frame->native.previous;
- if (previous == NULL) {
- return NXT_ERROR;
- }
+ ret ^= op - NJS_VMCODE_IF_TRUE_JUMP;
- njs_vm_scopes_restore(vm, frame, previous);
+ ret = ret ? (njs_ret_t) value2
+ : (njs_ret_t) sizeof(njs_vmcode_cond_jump_t);
- if (frame->native.size != 0) {
- vm->stack_size -= frame->native.size;
- nxt_mp_free(vm->mem_pool, frame);
- }
+ break;
- if (call) {
- return NXT_ERROR;
+ case NJS_VMCODE_IF_EQUAL_JUMP:
+ if (njs_values_strict_equal(value1, value2)) {
+ equal = (njs_vmcode_equal_jump_t *) pc;
+ ret = equal->offset;
+
+ } else {
+ ret = sizeof(njs_vmcode_3addr_t);
+ }
+
+ break;
+
+ case NJS_VMCODE_PROPERTY_INIT:
+ set = (njs_vmcode_prop_set_t *) pc;
+ retval = njs_vmcode_operand(vm, set->value);
+ ret = njs_vmcode_property_init(vm, value1, value2, retval);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_RETURN:
+ value2 = njs_vmcode_operand(vm, value2);
+
+ frame = (njs_frame_t *) vm->top_frame;
+
+ if (frame->native.ctor) {
+ if (njs_is_object(value2)) {
+ njs_release(vm, vm->scopes[NJS_SCOPE_ARGUMENTS]);
+
+ } else {
+ value2 = vm->scopes[NJS_SCOPE_ARGUMENTS];
+ }
+ }
+
+ previous = njs_function_previous_frame(&frame->native);
+
+ njs_vm_scopes_restore(vm, frame, previous);
+
+ /*
+ * If a retval is in a callee arguments scope it
+ * must be in the previous callee arguments scope.
+ */
+ retval = njs_vmcode_operand(vm, frame->retval);
+
+ /*
+ * GC: value external/internal++ depending on
+ * value and retval type
+ */
+ *retval = *value2;
+
+ njs_function_frame_free(vm, &frame->native);
+
+ ret = NJS_OK;
+ goto done;
+
+ case NJS_VMCODE_FUNCTION_FRAME:
+ function_frame = (njs_vmcode_function_frame_t *) pc;
+
+ /* TODO: external object instead of void this. */
+
+ ret = njs_function_frame_create(vm, value1,
+ &njs_value_undefined,
+ (uintptr_t) value2,
+ function_frame->code.ctor);
+
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto error;
+ }
+
+ ret = sizeof(njs_vmcode_function_frame_t);
+ break;
+
+ case NJS_VMCODE_METHOD_FRAME:
+ ret = njs_vmcode_method_frame(vm, value1, value2, pc);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_FUNCTION_CALL:
+ ret = njs_function_frame_invoke(vm, (njs_index_t) value2);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ ret = sizeof(njs_vmcode_function_call_t);
+ break;
+
+ case NJS_VMCODE_PROPERTY_NEXT:
+ if (!njs_is_external(value1)) {
+ pnext = (njs_vmcode_prop_next_t *) pc;
+ retval = njs_vmcode_operand(vm, pnext->retval);
+
+ next = value2->data.u.next;
+
+ if (next->index < next->array->length) {
+ *retval = next->array->data[next->index++];
+
+ ret = pnext->offset;
+ break;
+ }
+ }
+
+ ret = njs_vmcode_property_next(vm, value1, value2, pc);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_THIS:
+ frame = vm->active_frame;
+ this = (njs_vmcode_this_t *) pc;
+
+ retval = njs_vmcode_operand(vm, this->dst);
+ *retval = frame->native.arguments[0];
+
+ ret = sizeof(njs_vmcode_this_t);
+ break;
+
+ case NJS_VMCODE_ARGUMENTS:
+ ret = njs_vmcode_arguments(vm, pc);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_TRY_START:
+ ret = njs_vmcode_try_start(vm, value1, value2, pc);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_THROW:
+ value2 = njs_vmcode_operand(vm, value2);
+ vm->retval = *value2;
+ goto error;
+
+ case NJS_VMCODE_TRY_BREAK:
+ ret = njs_vmcode_try_break(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_TRY_CONTINUE:
+ ret = njs_vmcode_try_continue(vm, value1, value2);
+ break;
+
+ case NJS_VMCODE_TRY_END:
+ ret = njs_vmcode_try_end(vm, value1, value2);
+ break;
+
+ /*
+ * njs_vmcode_catch() is set on the start of a "catch" block to
+ * store exception and to remove a "try" block if there is no
+ * "finally" block or to update a catch address to the start of
+ * a "finally" block.
+ * njs_vmcode_catch() is set on the start of a "finally" block
+ * to store uncaught exception and to remove a "try" block.
+ */
+ case NJS_VMCODE_CATCH:
+ *value1 = vm->retval;
+
+ if ((njs_ret_t) value2 == sizeof(njs_vmcode_catch_t)) {
+ ret = njs_vmcode_try_end(vm, value1, value2);
+
+ } else {
+ vm->top_frame->exception.catch = pc + (njs_ret_t) value2;
+ ret = sizeof(njs_vmcode_catch_t);
+ }
+
+ break;
+
+ case NJS_VMCODE_FINALLY:
+ ret = njs_vmcode_finally(vm, value1, value2, pc);
+
+ switch (ret) {
+ case NJS_OK:
+ goto done;
+ case NJS_ERROR:
+ goto error;
+ }
+
+ break;
+
+ case NJS_VMCODE_REFERENCE_ERROR:
+ ret = njs_vmcode_reference_error(vm, pc);
+ goto error;
+
+ default:
+ njs_internal_error(vm, "%d has NO retval", op);
+ goto error;
}
}
+
+ pc += ret;
}
- /* NXT_ERROR, NJS_STOP. */
+error:
- return ret;
-}
+ ret = NXT_ERROR;
+ for ( ;; ) {
+ frame = (njs_frame_t *) vm->top_frame;
-nxt_int_t
-njs_vmcode_run(njs_vm_t *vm)
-{
- njs_ret_t ret;
+ catch = frame->native.exception.catch;
- vm->top_frame->call = 1;
+ if (catch != NULL) {
+ pc = catch;
- if (nxt_slow_path(vm->count > 128)) {
- njs_range_error(vm, "Maximum call stack size exceeded");
- return NXT_ERROR;
- }
+ if (vm->debug != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
- vm->count++;
+ goto next;
+ }
+
+ if (vm->debug != NULL
+ && njs_vm_add_backtrace_entry(vm, frame) != NXT_OK)
+ {
+ break;
+ }
+
+ previous = frame->native.previous;
+ if (previous == NULL) {
+ break;
+ }
- ret = njs_vmcode_interpreter(vm);
- if (ret == NJS_STOP) {
- ret = NJS_OK;
+ call = frame->native.call;
+
+ njs_vm_scopes_restore(vm, frame, previous);
+
+ if (frame->native.size != 0) {
+ vm->stack_size -= frame->native.size;
+ nxt_mp_free(vm->mem_pool, frame);
+ }
+
+ if (call) {
+ break;
+ }
}
+done:
+
vm->count--;
return ret;
}
-njs_ret_t
-njs_vmcode_object(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_object(njs_vm_t *vm, u_char *pc)
{
njs_object_t *object;
}
-njs_ret_t
-njs_vmcode_array(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_array(njs_vm_t *vm, u_char *pc)
{
uint32_t length;
njs_array_t *array;
njs_value_t *value;
njs_vmcode_array_t *code;
- code = (njs_vmcode_array_t *) vm->current;
+ code = (njs_vmcode_array_t *) pc;
array = njs_array_alloc(vm, code->length, NJS_ARRAY_SPARE);
}
-njs_ret_t
-njs_vmcode_function(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_function(njs_vm_t *vm, u_char *pc)
{
njs_function_t *function;
njs_function_lambda_t *lambda;
njs_vmcode_function_t *code;
- code = (njs_vmcode_function_t *) vm->current;
+ code = (njs_vmcode_function_t *) pc;
lambda = code->lambda;
function = njs_function_alloc(vm, lambda, vm->active_frame->closures, 0);
}
-njs_ret_t
-njs_vmcode_this(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_arguments(njs_vm_t *vm, u_char *pc)
{
- njs_frame_t *frame;
- njs_value_t *value;
- njs_vmcode_this_t *code;
-
- frame = (njs_frame_t *) vm->active_frame;
- code = (njs_vmcode_this_t *) vm->current;
-
- value = njs_vmcode_operand(vm, code->dst);
- *value = frame->native.arguments[0];
-
- return sizeof(njs_vmcode_this_t);
-}
-
-
-njs_ret_t
-njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
-{
- nxt_int_t ret;
- njs_frame_t *frame;
- njs_value_t *value;
- njs_vmcode_arguments_t *code;
+ nxt_int_t ret;
+ njs_frame_t *frame;
+ njs_value_t *value;
+ njs_vmcode_arguments_t *code;
frame = (njs_frame_t *) vm->active_frame;
}
}
- code = (njs_vmcode_arguments_t *) vm->current;
+ code = (njs_vmcode_arguments_t *) pc;
value = njs_vmcode_operand(vm, code->dst);
njs_set_object(value, frame->native.arguments_object);
}
-njs_ret_t
-njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_regexp(njs_vm_t *vm, u_char *pc)
{
njs_regexp_t *regexp;
njs_vmcode_regexp_t *code;
- code = (njs_vmcode_regexp_t *) vm->current;
+ code = (njs_vmcode_regexp_t *) pc;
regexp = njs_regexp_alloc(vm, code->pattern);
}
-njs_ret_t
+static njs_ret_t
njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *retval)
{
}
-njs_ret_t
+static njs_ret_t
njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
{
njs_object_t *object;
}
-njs_ret_t
-njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property)
-{
- njs_ret_t ret;
- njs_value_t *retval;
- njs_vmcode_prop_get_t *code;
-
- code = (njs_vmcode_prop_get_t *) vm->current;
- retval = njs_vmcode_operand(vm, code->value);
-
- ret = njs_value_property(vm, object, property, retval);
- if (nxt_slow_path(ret == NXT_ERROR)) {
- return ret;
- }
-
- vm->retval = *retval;
-
- return sizeof(njs_vmcode_prop_get_t);
-}
-
-
-njs_ret_t
+static njs_ret_t
njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property)
+ njs_value_t *property, njs_value_t *init)
{
- uint32_t index, size;
- njs_ret_t ret;
- njs_array_t *array;
- njs_value_t *init, *value, name;
- njs_object_t *obj;
- njs_object_prop_t *prop;
- nxt_lvlhsh_query_t lhq;
- njs_vmcode_prop_set_t *code;
-
- code = (njs_vmcode_prop_set_t *) vm->current;
- init = njs_vmcode_operand(vm, code->value);
+ uint32_t index, size;
+ njs_ret_t ret;
+ njs_array_t *array;
+ njs_value_t *value, name;
+ njs_object_t *obj;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
switch (object->type) {
case NJS_ARRAY:
}
-njs_ret_t
-njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property)
-{
- njs_ret_t ret;
- njs_value_t *value;
- njs_vmcode_prop_set_t *code;
-
- code = (njs_vmcode_prop_set_t *) vm->current;
- value = njs_vmcode_operand(vm, code->value);
-
- ret = njs_value_property_set(vm, object, property, value);
- if (nxt_slow_path(ret == NXT_ERROR)) {
- return ret;
- }
-
- return sizeof(njs_vmcode_prop_set_t);
-}
-
-
-njs_ret_t
+static njs_ret_t
njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *object, njs_value_t *property)
{
njs_ret_t ret;
}
-njs_ret_t
+static njs_ret_t
njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object,
njs_value_t *property)
{
}
-njs_ret_t
+static njs_ret_t
njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *invld)
+ njs_value_t *invld, u_char *pc)
{
void *obj;
njs_ret_t ret;
done:
- code = (njs_vmcode_prop_foreach_t *) vm->current;
+ code = (njs_vmcode_prop_foreach_t *) pc;
return code->offset;
}
-njs_ret_t
-njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value)
+static njs_ret_t
+njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value,
+ u_char *pc)
{
void *obj;
njs_ret_t ret;
const njs_extern_t *ext_proto;
njs_vmcode_prop_next_t *code;
- code = (njs_vmcode_prop_next_t *) vm->current;
+ code = (njs_vmcode_prop_next_t *) pc;
retval = njs_vmcode_operand(vm, code->retval);
if (njs_is_external(object)) {
}
-njs_ret_t
+static njs_ret_t
njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
njs_value_t *constructor)
{
}
-njs_ret_t
-njs_vmcode_increment(njs_vm_t *vm, njs_value_t *reference, njs_value_t *value)
-{
- double num;
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- num = njs_number(&numeric);
-
- } else {
- num = njs_number(value);
- }
-
- njs_release(vm, reference);
-
- njs_set_number(reference, num + 1.0);
- vm->retval = *reference;
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_decrement(njs_vm_t *vm, njs_value_t *reference, njs_value_t *value)
-{
- double num;
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- num = njs_number(&numeric);
-
- } else {
- num = njs_number(value);
- }
-
- njs_release(vm, reference);
-
- njs_set_number(reference, num - 1.0);
- vm->retval = *reference;
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_post_increment(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value)
-{
- double num;
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- num = njs_number(&numeric);
-
- } else {
- num = njs_number(value);
- }
-
- njs_release(vm, reference);
-
- njs_set_number(reference, num + 1.0);
- njs_set_number(&vm->retval, num);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_post_decrement(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value)
-{
- double num;
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- num = njs_number(&numeric);
-
- } else {
- num = njs_number(value);
- }
-
- njs_release(vm, reference);
-
- njs_set_number(reference, num - 1.0);
- njs_set_number(&vm->retval, num);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
+static njs_ret_t
njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
{
/* ECMAScript 5.1: null, array and regexp are objects. */
&njs_string_boolean,
&njs_string_number,
&njs_string_string,
- &njs_string_data,
- &njs_string_external,
- &njs_string_invalid,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
- &njs_string_undefined,
-
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_function,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- &njs_string_object,
- };
-
- vm->retval = *types[value->type];
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_void(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
-{
- vm->retval = njs_value_undefined;
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_delete(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_release(vm, value);
-
- vm->retval = njs_value_true;
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_unary_plus(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (ret != NXT_OK) {
- return ret;
- }
-
- value = &numeric;
- }
-
- njs_set_number(&vm->retval, njs_number(value));
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_unary_negation(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (ret != NXT_OK) {
- return ret;
- }
-
- value = &numeric;
- }
-
- njs_set_number(&vm->retval, -njs_number(value));
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_addition(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
-
- njs_value_t primitive1, primitive2, dst, *s1, *s2, *src;
-
- if (nxt_slow_path(!njs_is_primitive(val1))) {
-
- /*
- * ECMAScript 5.1:
- * Date should return String, other types sould return Number.
- */
-
- ret = njs_value_to_primitive(vm, &primitive1, val1, njs_is_date(val1));
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &primitive1;
- }
-
- if (nxt_slow_path(!njs_is_primitive(val2))) {
-
- /*
- * ECMAScript 5.1:
- * Date should return String, other types sould return Number.
- */
-
- ret = njs_value_to_primitive(vm, &primitive2, val2, njs_is_date(val2));
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &primitive2;
- }
-
- if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
- njs_set_number(&vm->retval, njs_number(val1) + njs_number(val2));
- return sizeof(njs_vmcode_3addr_t);
- }
-
- if (njs_is_string(val1)) {
- s1 = val1;
- s2 = &dst;
- src = val2;
-
- } else {
- s1 = &dst;
- s2 = val2;
- src = val1;
- }
-
- ret = njs_primitive_value_to_string(vm, &dst, src);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return njs_string_concat(vm, s1, s2);
- }
-
- return ret;
-}
-
-
-static njs_ret_t
-njs_string_concat(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- u_char *start;
- size_t size, length;
- njs_string_prop_t string1, string2;
-
- (void) njs_string_prop(&string1, val1);
- (void) njs_string_prop(&string2, val2);
-
- /*
- * A result of concatenation of Byte and ASCII or UTF-8 strings
- * is a Byte string.
- */
- if ((string1.length != 0 || string1.size == 0)
- && (string2.length != 0 || string2.size == 0))
- {
- length = string1.length + string2.length;
-
- } else {
- length = 0;
- }
-
- size = string1.size + string2.size;
-
- start = njs_string_alloc(vm, &vm->retval, size, length);
-
- if (nxt_slow_path(start == NULL)) {
- return NXT_ERROR;
- }
-
- (void) memcpy(start, string1.start, string1.size);
- (void) memcpy(start + string1.size, string2.start, string2.size);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_substraction(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- njs_set_number(&vm->retval, njs_number(val1) - njs_number(val2));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_multiplication(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- njs_set_number(&vm->retval, njs_number(val1) * njs_number(val2));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_exponentiation(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- double num, base, exponent;
- njs_ret_t ret;
- nxt_bool_t valid;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- base = njs_number(val1);
- exponent = njs_number(val2);
-
- /*
- * According to ES7:
- * 1. If exponent is NaN, the result should be NaN;
- * 2. The result of +/-1 ** +/-Infinity should be NaN.
- */
- valid = nxt_expect(1, fabs(base) != 1
- || (!isnan(exponent) && !isinf(exponent)));
-
- if (valid) {
- num = pow(base, exponent);
-
- } else {
- num = NAN;
- }
-
- njs_set_number(&vm->retval, num);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_division(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- njs_set_number(&vm->retval, njs_number(val1) / njs_number(val2));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_remainder(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- double num;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num = fmod(njs_number(val1), njs_number(val2));
- njs_set_number(&vm->retval, num);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_left_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- int32_t num1;
- uint32_t num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num1 = njs_number_to_int32(njs_number(val1));
- num2 = njs_number_to_uint32(njs_number(val2));
- njs_set_int32(&vm->retval, num1 << (num2 & 0x1f));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_right_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- int32_t num1;
- uint32_t num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num1 = njs_number_to_int32(njs_number(val1));
- num2 = njs_number_to_uint32(njs_number(val2));
- njs_set_int32(&vm->retval, num1 >> (num2 & 0x1f));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_unsigned_right_shift(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2)
-{
- uint32_t num1, num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num1 = njs_number_to_uint32(njs_number(val1));
- num2 = njs_number_to_uint32(njs_number(val2));
- njs_set_uint32(&vm->retval, num1 >> (num2 & 0x1f));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_logical_not(njs_vm_t *vm, njs_value_t *value, njs_value_t *inlvd)
-{
- njs_set_boolean(&vm->retval, !njs_is_true(value));
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_test_if_true(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_vmcode_test_jump_t *test_jump;
-
- vm->retval = *value;
-
- if (njs_is_true(value)) {
- test_jump = (njs_vmcode_test_jump_t *) vm->current;
- return test_jump->offset;
- }
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_test_if_false(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_vmcode_test_jump_t *test_jump;
-
- vm->retval = *value;
-
- if (!njs_is_true(value)) {
- test_jump = (njs_vmcode_test_jump_t *) vm->current;
- return test_jump->offset;
- }
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_bitwise_not(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_ret_t ret;
- njs_value_t numeric;
-
- if (nxt_slow_path(!njs_is_numeric(value))) {
- ret = njs_value_to_numeric(vm, &numeric, value);
- if (ret != NXT_OK) {
- return ret;
- }
-
- value = &numeric;
- }
-
- njs_set_int32(&vm->retval, ~njs_number_to_integer(njs_number(value)));
-
- return sizeof(njs_vmcode_2addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_bitwise_and(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- int32_t num1, num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num1 = njs_number_to_integer(njs_number(val1));
- num2 = njs_number_to_integer(njs_number(val2));
- njs_set_int32(&vm->retval, num1 & num2);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_bitwise_xor(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- int32_t num1, num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val2 = &numeric2;
- }
-
- num1 = njs_number_to_integer(njs_number(val1));
- num2 = njs_number_to_integer(njs_number(val2));
- njs_set_int32(&vm->retval, num1 ^ num2);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_bitwise_or(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- int32_t num1, num2;
- njs_ret_t ret;
- njs_value_t numeric1, numeric2;
-
- if (nxt_slow_path(!njs_is_numeric(val1))) {
- ret = njs_value_to_numeric(vm, &numeric1, val1);
- if (ret != NXT_OK) {
- return ret;
- }
-
- val1 = &numeric1;
- }
-
- if (nxt_slow_path(!njs_is_numeric(val2))) {
- ret = njs_value_to_numeric(vm, &numeric2, val2);
- if (ret != NXT_OK) {
- return ret;
- }
+ &njs_string_data,
+ &njs_string_external,
+ &njs_string_invalid,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
+ &njs_string_undefined,
- val2 = &numeric2;
- }
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_function,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
+ };
- num1 = njs_number_to_integer(njs_number(val1));
- num2 = njs_number_to_integer(njs_number(val2));
- njs_set_int32(&vm->retval, num1 | num2);
+ vm->retval = *types[value->type];
- return sizeof(njs_vmcode_3addr_t);
+ return sizeof(njs_vmcode_2addr_t);
}
-njs_ret_t
-njs_vmcode_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
+static njs_ret_t
+njs_string_concat(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
{
- njs_ret_t ret;
-
- ret = njs_values_equal(vm, val1, val2);
+ u_char *start;
+ size_t size, length;
+ njs_string_prop_t string1, string2;
- if (nxt_fast_path(ret >= 0)) {
+ (void) njs_string_prop(&string1, val1);
+ (void) njs_string_prop(&string2, val2);
- njs_set_boolean(&vm->retval, ret != 0);
+ /*
+ * A result of concatenation of Byte and ASCII or UTF-8 strings
+ * is a Byte string.
+ */
+ if ((string1.length != 0 || string1.size == 0)
+ && (string2.length != 0 || string2.size == 0))
+ {
+ length = string1.length + string2.length;
- return sizeof(njs_vmcode_3addr_t);
+ } else {
+ length = 0;
}
- return ret;
-}
-
-
-njs_ret_t
-njs_vmcode_not_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
-
- ret = njs_values_equal(vm, val1, val2);
-
- if (nxt_fast_path(ret >= 0)) {
+ size = string1.size + string2.size;
- njs_set_boolean(&vm->retval, ret == 0);
+ start = njs_string_alloc(vm, &vm->retval, size, length);
- return sizeof(njs_vmcode_3addr_t);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
}
- return ret;
+ (void) memcpy(start, string1.start, string1.size);
+ (void) memcpy(start + string1.size, string2.start, string2.size);
+
+ return sizeof(njs_vmcode_3addr_t);
}
}
-nxt_inline njs_ret_t
-njs_values_to_primitive(njs_vm_t *vm, njs_value_t *primitive1,
- njs_value_t **val1, njs_value_t *primitive2, njs_value_t **val2)
-{
- njs_ret_t ret;
-
- if (nxt_slow_path(!njs_is_primitive(*val1))) {
- ret = njs_value_to_primitive(vm, primitive1, *val1, 0);
- if (ret != NXT_OK) {
- return ret;
- }
-
- *val1 = primitive1;
- }
-
- if (nxt_slow_path(!njs_is_primitive(*val2))) {
- ret = njs_value_to_primitive(vm, primitive2, *val2, 0);
- if (ret != NXT_OK) {
- return ret;
- }
-
- *val2 = primitive2;
- }
-
- return NXT_OK;
-}
-
-
-njs_ret_t
-njs_vmcode_less(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t primitive1, primitive2;
-
- ret = njs_values_to_primitive(vm, &primitive1, &val1, &primitive2, &val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- ret = njs_primitive_values_compare(vm, val1, val2);
-
- njs_set_boolean(&vm->retval, ret > 0);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_greater(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t primitive1, primitive2;
-
- ret = njs_values_to_primitive(vm, &primitive1, &val1, &primitive2, &val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- ret = njs_primitive_values_compare(vm, val2, val1);
-
- njs_set_boolean(&vm->retval, ret > 0);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_less_or_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t primitive1, primitive2;
-
- ret = njs_values_to_primitive(vm, &primitive1, &val1, &primitive2, &val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- ret = njs_primitive_values_compare(vm, val2, val1);
-
- njs_set_boolean(&vm->retval, ret == 0);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_greater_or_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_ret_t ret;
- njs_value_t primitive1, primitive2;
-
- ret = njs_values_to_primitive(vm, &primitive1, &val1, &primitive2, &val2);
- if (ret != NXT_OK) {
- return ret;
- }
-
- ret = njs_primitive_values_compare(vm, val1, val2);
-
- njs_set_boolean(&vm->retval, ret == 0);
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
/*
* ECMAScript 5.1: 11.8.5
* njs_primitive_values_compare() returns
}
-njs_ret_t
-njs_vmcode_strict_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_set_boolean(&vm->retval, njs_values_strict_equal(val1, val2));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_strict_not_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_set_boolean(&vm->retval, !njs_values_strict_equal(val1, val2));
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_move(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- vm->retval = *value;
-
- njs_retain(value);
-
- return sizeof(njs_vmcode_move_t);
-}
-
-
-njs_ret_t
-njs_vmcode_jump(njs_vm_t *vm, njs_value_t *invld, njs_value_t *offset)
-{
- return (njs_ret_t) offset;
-}
-
-
-njs_ret_t
-njs_vmcode_if_true_jump(njs_vm_t *vm, njs_value_t *cond, njs_value_t *offset)
-{
- if (njs_is_true(cond)) {
- return (njs_ret_t) offset;
- }
-
- return sizeof(njs_vmcode_cond_jump_t);
-}
-
-
-njs_ret_t
-njs_vmcode_if_false_jump(njs_vm_t *vm, njs_value_t *cond, njs_value_t *offset)
-{
- if (njs_is_true(cond)) {
- return sizeof(njs_vmcode_cond_jump_t);
- }
-
- return (njs_ret_t) offset;
-}
-
-
-njs_ret_t
-njs_vmcode_if_equal_jump(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
-{
- njs_vmcode_equal_jump_t *jump;
-
- if (njs_values_strict_equal(val1, val2)) {
- jump = (njs_vmcode_equal_jump_t *) vm->current;
- return jump->offset;
- }
-
- return sizeof(njs_vmcode_3addr_t);
-}
-
-
-njs_ret_t
-njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs)
-{
- njs_ret_t ret;
- njs_vmcode_function_frame_t *function;
-
- function = (njs_vmcode_function_frame_t *) vm->current;
-
- /* TODO: external object instead of void this. */
-
- ret = njs_function_frame_create(vm, value, &njs_value_undefined,
- (uintptr_t) nargs, function->code.ctor);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_function_frame_t);
- }
-
- return ret;
-}
-
-
static njs_ret_t
njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
const njs_value_t *this, uintptr_t nargs, nxt_bool_t ctor)
}
-njs_ret_t
-njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
+static njs_ret_t
+njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name,
+ u_char *pc)
{
njs_ret_t ret;
nxt_str_t string;
njs_vmcode_method_frame_t *method;
value = NULL;
- method = (njs_vmcode_method_frame_t *) vm->current;
+ method = (njs_vmcode_method_frame_t *) pc;
njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
}
-njs_ret_t
-njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
-{
- njs_ret_t ret;
-
- ret = njs_function_frame_invoke(vm, (njs_index_t) retval);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- return sizeof(njs_vmcode_function_call_t);
-}
-
-
-njs_ret_t
+static njs_ret_t
njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
{
njs_value_t *value;
}
}
- vm->current = frame->return_address;
-
previous = njs_function_previous_frame(&frame->native);
njs_vm_scopes_restore(vm, frame, previous);
njs_function_frame_free(vm, &frame->native);
- return NJS_STOP;
-}
-
-
-njs_ret_t
-njs_vmcode_stop(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
-{
- njs_value_t *value;
-
- value = njs_vmcode_operand(vm, retval);
-
- vm->retval = *value;
-
- return NJS_STOP;
+ return NJS_OK;
}
* "finally" blocks and to initialize a value to track uncaught exception.
*/
-njs_ret_t
+static njs_ret_t
njs_vmcode_try_start(njs_vm_t *vm, njs_value_t *exception_value,
- njs_value_t *offset)
+ njs_value_t *offset, u_char *pc)
{
njs_value_t *exit_value;
njs_exception_t *e;
vm->top_frame->exception.next = e;
}
- vm->top_frame->exception.catch = vm->current + (njs_ret_t) offset;
+ vm->top_frame->exception.catch = pc + (njs_ret_t) offset;
njs_set_invalid(exception_value);
- try_start = (njs_vmcode_try_start_t *) vm->current;
+ try_start = (njs_vmcode_try_start_t *) pc;
exit_value = njs_vmcode_operand(vm, try_start->exit_value);
njs_set_invalid(exit_value);
* the nearest try_end block. The exit_value is checked by njs_vmcode_finally().
*/
-njs_ret_t
+static njs_ret_t
njs_vmcode_try_break(njs_vm_t *vm, njs_value_t *exit_value,
njs_value_t *offset)
{
* the nearest try_end block. The exit_value is checked by njs_vmcode_finally().
*/
-njs_ret_t
+static njs_ret_t
njs_vmcode_try_continue(njs_vm_t *vm, njs_value_t *exit_value,
njs_value_t *offset)
{
return (njs_ret_t) offset;
}
-/*
- * njs_vmcode_try_return() saves a return value to use it later by
- * njs_vmcode_finally(), and jumps to the nearest try_break block.
- */
-
-njs_ret_t
-njs_vmcode_try_return(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
-{
- njs_vmcode_try_return_t *try_return;
-
- vm->retval = *value;
-
- njs_retain(value);
-
- try_return = (njs_vmcode_try_return_t *) vm->current;
-
- return try_return->offset;
-}
-
/*
* njs_vmcode_try_end() is set on the end of a "try" block to remove the block.
* It is also set on the end of a "catch" block followed by a "finally" block.
*/
-njs_ret_t
+static njs_ret_t
njs_vmcode_try_end(njs_vm_t *vm, njs_value_t *invld, njs_value_t *offset)
{
njs_exception_t *e;
}
-njs_ret_t
-njs_vmcode_throw(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
-{
- njs_value_t *value;
-
- value = njs_vmcode_operand(vm, retval);
-
- vm->retval = *value;
-
- return NXT_ERROR;
-}
-
-
-/*
- * njs_vmcode_catch() is set on the start of a "catch" block to store
- * exception and to remove a "try" block if there is no "finally" block
- * or to update a catch address to the start of a "finally" block.
- * njs_vmcode_catch() is set on the start of a "finally" block to store
- * uncaught exception and to remove a "try" block.
- */
-
-njs_ret_t
-njs_vmcode_catch(njs_vm_t *vm, njs_value_t *exception, njs_value_t *offset)
-{
- *exception = vm->retval;
-
- if ((njs_ret_t) offset == sizeof(njs_vmcode_catch_t)) {
- return njs_vmcode_try_end(vm, exception, offset);
- }
-
- vm->top_frame->exception.catch = vm->current + (njs_ret_t) offset;
-
- return sizeof(njs_vmcode_catch_t);
-}
-
-
/*
* njs_vmcode_finally() is set on the end of a "finally" or a "catch" block.
* 1) to throw uncaught exception.
* 3) to finalize "return" instruction from "try" block.
*/
-njs_ret_t
-njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
+static njs_ret_t
+njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval,
+ u_char *pc)
{
njs_value_t *exception_value, *exit_value;
njs_vmcode_finally_t *finally;
return NXT_ERROR;
}
- finally = (njs_vmcode_finally_t *) vm->current;
+ finally = (njs_vmcode_finally_t *) pc;
exit_value = njs_vmcode_operand(vm, finally->exit_value);
/*
}
-njs_ret_t
-njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1,
- njs_value_t *invld2)
+static njs_ret_t
+njs_vmcode_reference_error(njs_vm_t *vm, u_char *pc)
{
nxt_str_t *file;
njs_vmcode_reference_error_t *ref_err;
- ref_err = (njs_vmcode_reference_error_t *) vm->current;
+ ref_err = (njs_vmcode_reference_error_t *) pc;
file = &ref_err->file;
* Negative return values handled by nJSVM interpreter as special events.
* The values must be in range from -1 to -11, because -12 is minimal jump
* offset on 32-bit platforms.
+ * 0 (NJS_OK/NXT_OK) : njs_vmcode_stop() has stopped execution,
+ * execution successfully finished
* -1 (NJS_ERROR/NXT_ERROR): error or exception;
- * -2 (NJS_AGAIN/NXT_AGAIN): postpone nJSVM execution;
- * -3: not used;
- * -4 (NJS_STOP/NXT_DONE): njs_vmcode_stop() has stopped execution,
- * execution has completed successfully;
- * -5 .. -11: not used.
+ * -2 .. -11: not used.
*/
-#define NJS_STOP NXT_DONE
-
/* The last return value which preempts execution. */
-#define NJS_PREEMPT (-11)
-
-
-typedef njs_ret_t (*njs_vmcode_operation_t)(njs_vm_t *vm, njs_value_t *value1,
- njs_value_t *value2);
-
-
-#define NJS_VMCODE_3OPERANDS 0
-#define NJS_VMCODE_2OPERANDS 1
-#define NJS_VMCODE_1OPERAND 2
-#define NJS_VMCODE_NO_OPERAND 3
-
-#define NJS_VMCODE_NO_RETVAL 0
-#define NJS_VMCODE_RETVAL 1
+#define NJS_PREEMPT (-11)
+
+
+typedef uint8_t njs_vmcode_operation_t;
+
+
+#define NJS_VMCODE_3OPERANDS 0
+#define NJS_VMCODE_2OPERANDS 1
+#define NJS_VMCODE_1OPERAND 2
+#define NJS_VMCODE_NO_OPERAND 3
+
+#define NJS_VMCODE_NO_RETVAL 0
+#define NJS_VMCODE_RETVAL 1
+
+#define VMCODE0(n) (n)
+#define VMCODE1(n) ((n) + 128)
+
+#define NJS_VMCODE_STOP VMCODE0(0)
+#define NJS_VMCODE_JUMP VMCODE0(1)
+#define NJS_VMCODE_PROPERTY_SET VMCODE0(2)
+#define NJS_VMCODE_IF_TRUE_JUMP VMCODE0(4)
+#define NJS_VMCODE_IF_FALSE_JUMP VMCODE0(5)
+#define NJS_VMCODE_IF_EQUAL_JUMP VMCODE0(6)
+#define NJS_VMCODE_PROPERTY_INIT VMCODE0(7)
+#define NJS_VMCODE_RETURN VMCODE0(8)
+#define NJS_VMCODE_FUNCTION_FRAME VMCODE0(9)
+#define NJS_VMCODE_METHOD_FRAME VMCODE0(10)
+#define NJS_VMCODE_FUNCTION_CALL VMCODE0(11)
+#define NJS_VMCODE_PROPERTY_NEXT VMCODE0(16)
+#define NJS_VMCODE_THIS VMCODE0(17)
+#define NJS_VMCODE_ARGUMENTS VMCODE0(18)
+
+#define NJS_VMCODE_TRY_START VMCODE0(32)
+#define NJS_VMCODE_THROW VMCODE0(33)
+#define NJS_VMCODE_TRY_BREAK VMCODE0(34)
+#define NJS_VMCODE_TRY_CONTINUE VMCODE0(35)
+#define NJS_VMCODE_TRY_END VMCODE0(37)
+#define NJS_VMCODE_CATCH VMCODE0(38)
+#define NJS_VMCODE_FINALLY VMCODE0(39)
+#define NJS_VMCODE_REFERENCE_ERROR VMCODE0(40)
+
+#define NJS_VMCODE_MOVE VMCODE1(0)
+#define NJS_VMCODE_PROPERTY_GET VMCODE1(1)
+#define NJS_VMCODE_INCREMENT VMCODE1(2)
+#define NJS_VMCODE_POST_INCREMENT VMCODE1(3)
+#define NJS_VMCODE_DECREMENT VMCODE1(4)
+#define NJS_VMCODE_POST_DECREMENT VMCODE1(5)
+#define NJS_VMCODE_TRY_RETURN VMCODE1(6)
+
+#define NJS_VMCODE_LESS VMCODE1(8)
+#define NJS_VMCODE_GREATER VMCODE1(9)
+#define NJS_VMCODE_LESS_OR_EQUAL VMCODE1(10)
+#define NJS_VMCODE_GREATER_OR_EQUAL VMCODE1(11)
+#define NJS_VMCODE_ADDITION VMCODE1(12)
+#define NJS_VMCODE_EQUAL VMCODE1(13)
+#define NJS_VMCODE_NOT_EQUAL VMCODE1(14)
+
+#define NJS_VMCODE_SUBSTRACTION VMCODE1(16)
+#define NJS_VMCODE_MULTIPLICATION VMCODE1(17)
+#define NJS_VMCODE_EXPONENTIATION VMCODE1(18)
+#define NJS_VMCODE_DIVISION VMCODE1(19)
+#define NJS_VMCODE_REMAINDER VMCODE1(20)
+#define NJS_VMCODE_BITWISE_AND VMCODE1(21)
+#define NJS_VMCODE_BITWISE_OR VMCODE1(22)
+#define NJS_VMCODE_BITWISE_XOR VMCODE1(23)
+#define NJS_VMCODE_LEFT_SHIFT VMCODE1(24)
+#define NJS_VMCODE_RIGHT_SHIFT VMCODE1(25)
+#define NJS_VMCODE_UNSIGNED_RIGHT_SHIFT VMCODE1(26)
+#define NJS_VMCODE_OBJECT_COPY VMCODE1(27)
+#define NJS_VMCODE_TEMPLATE_LITERAL VMCODE1(28)
+#define NJS_VMCODE_PROPERTY_IN VMCODE1(29)
+#define NJS_VMCODE_PROPERTY_DELETE VMCODE1(30)
+#define NJS_VMCODE_PROPERTY_FOREACH VMCODE1(31)
+
+#define NJS_VMCODE_STRICT_EQUAL VMCODE1(32)
+#define NJS_VMCODE_STRICT_NOT_EQUAL VMCODE1(33)
+
+#define NJS_VMCODE_TEST_IF_TRUE VMCODE1(34)
+#define NJS_VMCODE_TEST_IF_FALSE VMCODE1(35)
+
+#define NJS_VMCODE_UNARY_PLUS VMCODE1(36)
+#define NJS_VMCODE_UNARY_NEGATION VMCODE1(37)
+#define NJS_VMCODE_BITWISE_NOT VMCODE1(38)
+#define NJS_VMCODE_LOGICAL_NOT VMCODE1(39)
+#define NJS_VMCODE_OBJECT VMCODE1(40)
+#define NJS_VMCODE_ARRAY VMCODE1(41)
+#define NJS_VMCODE_FUNCTION VMCODE1(42)
+#define NJS_VMCODE_REGEXP VMCODE1(43)
+
+#define NJS_VMCODE_INSTANCE_OF VMCODE1(44)
+#define NJS_VMCODE_TYPEOF VMCODE1(45)
+#define NJS_VMCODE_VOID VMCODE1(46)
+#define NJS_VMCODE_DELETE VMCODE1(47)
+
+#define NJS_VMCODE_NOP 255
typedef struct {
} njs_vmcode_reference_error_t;
-nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
-nxt_int_t njs_vmcode_run(njs_vm_t *vm);
-
-njs_ret_t njs_vmcode_object(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_array(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
-njs_ret_t njs_vmcode_this(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
-njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
-njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
-njs_ret_t njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-
-njs_ret_t njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property);
-njs_ret_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property);
-njs_ret_t njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property);
-njs_ret_t njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *property,
- njs_value_t *object);
-njs_ret_t njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property);
-njs_ret_t njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *value);
-njs_ret_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *constructor);
-
-njs_ret_t njs_vmcode_increment(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value);
-njs_ret_t njs_vmcode_decrement(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value);
-njs_ret_t njs_vmcode_post_increment(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value);
-njs_ret_t njs_vmcode_post_decrement(njs_vm_t *vm, njs_value_t *reference,
- njs_value_t *value);
-njs_ret_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_void(njs_vm_t *vm, njs_value_t *invld1,
- njs_value_t *invld2);
-njs_ret_t njs_vmcode_delete(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_unary_plus(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_unary_negation(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_addition(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_substraction(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_multiplication(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_exponentiation(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_division(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_remainder(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_logical_not(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *inlvd);
-njs_ret_t njs_vmcode_test_if_true(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_test_if_false(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_bitwise_not(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *inlvd);
-njs_ret_t njs_vmcode_bitwise_and(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_bitwise_xor(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_bitwise_or(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_left_shift(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_right_shift(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_unsigned_right_shift(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2);
-njs_ret_t njs_vmcode_not_equal(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_less(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2);
-njs_ret_t njs_vmcode_greater(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_less_or_equal(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_greater_or_equal(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_strict_equal(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-njs_ret_t njs_vmcode_strict_not_equal(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-
-njs_ret_t njs_vmcode_move(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld);
-
-njs_ret_t njs_vmcode_jump(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_if_true_jump(njs_vm_t *vm, njs_value_t *cond,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_if_false_jump(njs_vm_t *vm, njs_value_t *cond,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_if_equal_jump(njs_vm_t *vm, njs_value_t *val1,
- njs_value_t *val2);
-
-njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *nargs);
-njs_ret_t njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *method);
-njs_ret_t njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *retval);
-njs_ret_t njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *retval);
-njs_ret_t njs_vmcode_stop(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *retval);
-
-njs_ret_t njs_vmcode_try_start(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_try_break(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_try_continue(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_try_return(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_try_end(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *offset);
-njs_ret_t njs_vmcode_throw(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *retval);
-njs_ret_t njs_vmcode_catch(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *exception);
-njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *retval);
-njs_ret_t njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1,
- njs_value_t *invld2);
+nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm, u_char *code);
#endif /* _NJS_VMCODE_H_INCLUDED_ */
{ nxt_string("'\x00абвгдеёжз'.toUpperCase().length"),
nxt_string("10") },
+#if 0 /* FIXME */
#if (!NXT_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
{ nxt_string("var a = [], code;"
"for (code = 0; code <= 1114111; code++) {"
" a.push(code);"
"} a"),
nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") },
+#endif
#endif
{ nxt_string("'abc'.trim()"),
{ nxt_string("(function() { try { return ['a'];} finally {} } )()"),
nxt_string("a") },
+ { nxt_string("function f(){}; try {f((new RegExp('a**')))} catch (e) { }"),
+ nxt_string("undefined") },
+
+ { nxt_string("function f(){}; try {f(f((new RegExp('a**'))))} catch (e) { }"),
+ nxt_string("undefined") },
+
+ { nxt_string("function f(){}; (function(){try {f(f((new RegExp('a**'))))} catch (e) { return 1}})()"),
+ nxt_string("1") },
+
{ nxt_string("var o = { valueOf: function() { return '3' } }; --o"),
nxt_string("2") },