each->index = n;
if (n > 0) {
- vm->current -= sizeof(njs_vmcode_call_t);
+ vm->current -= sizeof(njs_vmcode_function_call_t);
}
nargs = param->nargs;
func = (nargs != 0) ? &args[0] : (njs_value_t *) &njs_value_void;
- vm->current -= sizeof(njs_vmcode_call_t);
+ vm->current -= sizeof(njs_vmcode_function_call_t);
return njs_function_apply(vm, func, &p);
}
func = (nargs != 0) ? &args[0] : (njs_value_t *) &njs_value_void;
- vm->current -= sizeof(njs_vmcode_call_t);
+ vm->current -= sizeof(njs_vmcode_function_call_t);
return njs_function_apply(vm, func, &p);
}
for (i = NJS_FUNCTION_OBJECT; i < NJS_FUNCTION_MAX; i++) {
functions[i].native = 1;
functions[i].args_offset = 1;
- functions[i].code.native = native_functions[i];
+ functions[i].u.native = native_functions[i];
ret = njs_object_hash_create(vm, &functions[i].object.shared_hash,
function_init[i]->properties,
static njs_code_name_t code_names[] = {
- { njs_vmcode_object_create, sizeof(njs_vmcode_object_t),
- nxt_string("OBJECT CREATE ") },
- { njs_vmcode_function_create, sizeof(njs_vmcode_function_create_t),
- nxt_string("FUNCTION CREATE ") },
- { njs_vmcode_regexp_create, sizeof(njs_vmcode_regexp_t),
- nxt_string("REGEXP CREATE ") },
+ { njs_vmcode_object, sizeof(njs_vmcode_object_t),
+ nxt_string("OBJECT ") },
+ { njs_vmcode_function, sizeof(njs_vmcode_function_t),
+ nxt_string("FUNCTION ") },
+ { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
+ nxt_string("REGEXP ") },
{ njs_vmcode_property_get, sizeof(njs_vmcode_prop_get_t),
nxt_string("PROPERTY GET ") },
{ njs_vmcode_instance_of, sizeof(njs_vmcode_instance_of_t),
nxt_string("INSTANCE OF ") },
- { njs_vmcode_function, sizeof(njs_vmcode_function_t),
- nxt_string("FUNCTION ") },
- { njs_vmcode_call, sizeof(njs_vmcode_call_t),
- nxt_string("CALL ") },
- { njs_vmcode_return, sizeof(njs_vmcode_stop_t),
+ { njs_vmcode_function_frame, sizeof(njs_vmcode_function_frame_t),
+ nxt_string("FUNCTION FRAME ") },
+ { njs_vmcode_function_call, sizeof(njs_vmcode_function_call_t),
+ nxt_string("FUNCTION CALL ") },
+ { njs_vmcode_return, sizeof(njs_vmcode_return_t),
nxt_string("RETURN ") },
{ njs_vmcode_stop, sizeof(njs_vmcode_stop_t),
nxt_string("STOP ") },
static void
njs_disassemble(u_char *start, u_char *end)
{
- u_char *p;
- nxt_str_t *name;
- nxt_uint_t n;
- const char *sign;
- njs_code_name_t *code_name;
- njs_vmcode_jump_t *jump;
- njs_vmcode_1addr_t *code1;
- njs_vmcode_2addr_t *code2;
- njs_vmcode_3addr_t *code3;
- njs_vmcode_array_t *array;
- njs_vmcode_catch_t *catch;
- njs_vmcode_method_t *method;
- njs_vmcode_try_end_t *try_end;
- njs_vmcode_try_start_t *try_start;
- njs_vmcode_operation_t operation;
- njs_vmcode_cond_jump_t *cond_jump;
- njs_vmcode_prop_each_t *each;
- njs_vmcode_prop_start_t *prop_start;
+ u_char *p;
+ nxt_str_t *name;
+ nxt_uint_t n;
+ const char *sign;
+ njs_code_name_t *code_name;
+ njs_vmcode_jump_t *jump;
+ njs_vmcode_1addr_t *code1;
+ njs_vmcode_2addr_t *code2;
+ njs_vmcode_3addr_t *code3;
+ njs_vmcode_array_t *array;
+ njs_vmcode_catch_t *catch;
+ njs_vmcode_try_end_t *try_end;
+ njs_vmcode_try_start_t *try_start;
+ njs_vmcode_operation_t operation;
+ njs_vmcode_cond_jump_t *cond_jump;
+ njs_vmcode_prop_each_t *each;
+ njs_vmcode_prop_start_t *prop_start;
+ njs_vmcode_method_frame_t *method;
p = start;
while (p < end) {
operation = *(njs_vmcode_operation_t *) p;
- if (operation == njs_vmcode_array_create) {
+ if (operation == njs_vmcode_array) {
array = (njs_vmcode_array_t *) p;
p += sizeof(njs_vmcode_array_t);
- printf("ARRAY CREATE %04lX %ld\n",
+ printf("ARRAY %04lX %ld\n",
array->retval, array->length);
continue;
continue;
}
- if (operation == njs_vmcode_method) {
- method = (njs_vmcode_method_t *) p;
- p += sizeof(njs_vmcode_method_t);
+ if (operation == njs_vmcode_method_frame) {
+ method = (njs_vmcode_method_frame_t *) p;
+ p += sizeof(njs_vmcode_method_frame_t);
- printf("METHOD %04lX %04lX %04lX %d\n", method->function,
+ printf("METHOD FRAME %04lX %04lX %d\n",
method->object, method->method, method->code.nargs);
continue;
#include <string.h>
-static const njs_vmcode_1addr_t njs_trap_strings[] = {
- { .code = { .operation = njs_vmcode_string_primitive,
- .operands = NJS_VMCODE_1OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL },
- .index = 0 },
- { .code = { .operation = njs_vmcode_string_primitive,
- .operands = NJS_VMCODE_1OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL },
- .index = 1 },
- { .code = { .operation = njs_vmcode_restart,
- .operands = NJS_VMCODE_NO_OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vmcode_1addr_t njs_trap_numbers[] = {
- { .code = { .operation = njs_vmcode_number_primitive,
- .operands = NJS_VMCODE_1OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL },
- .index = 0 },
- { .code = { .operation = njs_vmcode_number_primitive,
- .operands = NJS_VMCODE_1OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL },
- .index = 1 },
- { .code = { .operation = njs_vmcode_restart,
- .operands = NJS_VMCODE_NO_OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vmcode_1addr_t njs_trap_number[] = {
- { .code = { .operation = njs_vmcode_number_primitive,
- .operands = NJS_VMCODE_1OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL },
- .index = 0 },
- { .code = { .operation = njs_vmcode_restart,
- .operands = NJS_VMCODE_NO_OPERAND,
- .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vm_trap_t njs_vm_traps[] = {
- /* NJS_TRAP_PROPERTY */ { &njs_trap_strings[1], 0 },
- /* NJS_TRAP_STRINGS */ { &njs_trap_strings[0], 0 },
- /* NJS_TRAP_INCDEC */ { &njs_trap_numbers[1], 1 },
- /* NJS_TRAP_NUMBERS */ { &njs_trap_numbers[0], 0 },
- /* NJS_TRAP_NUMBER */ { &njs_trap_number[0], 0 },
-};
-
-
njs_function_t *
njs_function_alloc(njs_vm_t *vm)
{
- njs_function_t *func;
- njs_function_script_t *script;
+ njs_function_t *function;
- func = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
+ function = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
- if (nxt_fast_path(func != NULL)) {
- func->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
- func->args_offset = 1;
+ if (nxt_fast_path(function != NULL)) {
+ function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
+ function->args_offset = 1;
- script = nxt_mem_cache_zalloc(vm->mem_cache_pool,
- sizeof(njs_function_script_t));
- if (nxt_slow_path(script == NULL)) {
+ function->u.lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+ sizeof(njs_function_lambda_t));
+ if (nxt_slow_path(function->u.lambda == NULL)) {
return NULL;
}
-
- func->code.script = script;
}
- return func;
+ return function;
}
-nxt_noinline njs_value_t *
-njs_vmcode_native_frame(njs_vm_t *vm, njs_value_t *method, uintptr_t nargs,
- nxt_bool_t ctor)
+njs_value_t *
+njs_function_native_frame(njs_vm_t *vm, njs_native_t native, size_t local_size,
+ njs_vmcode_t *code)
{
- size_t size, spare_size;
+ size_t size;
njs_value_t *this;
njs_native_frame_t *frame;
- size = NJS_NATIVE_FRAME_SIZE
- + method->data.string_size
- + nargs * sizeof(njs_value_t);
-
- if (nxt_fast_path(size <= vm->frame->size)) {
- frame = (njs_native_frame_t *) vm->frame->last;
- frame->size = vm->frame->size - size;
- frame->start = 0;
+ size = NJS_NATIVE_FRAME_SIZE + local_size
+ + code->nargs * sizeof(njs_value_t);
- } else {
- spare_size = size + NJS_FRAME_SPARE_SIZE;
- spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE);
-
- frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
- spare_size);
- if (nxt_slow_path(frame == NULL)) {
- return NULL;
- }
-
- frame->size = spare_size - size;
- frame->start = 1;
+ frame = njs_function_frame_alloc(vm, size);
+ if (nxt_slow_path(frame == NULL)) {
+ return NULL;
}
- frame->ctor = ctor;
- frame->reentrant = 0;
- frame->trap_reference = 0;
-
- frame->u.exception.next = NULL;
- frame->u.exception.catch = NULL;
-
- frame->last = (u_char *) frame + size;
- frame->previous = vm->frame;
- vm->frame = frame;
+ frame->u.native = native;
+ frame->native = 1;
+ frame->ctor = code->ctor;
- this = (njs_value_t *)
- ((u_char *) njs_native_data(frame) + method->data.string_size);
+ this = (njs_value_t *) ((u_char *) njs_native_data(frame) + local_size);
frame->arguments = this + 1;
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = frame->arguments;
}
-njs_ret_t
-njs_vmcode_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
- njs_value_t *value2)
+nxt_noinline njs_native_frame_t *
+njs_function_frame_alloc(njs_vm_t *vm, size_t size)
{
- size_t size, spare_size;
- njs_value_t *values;
+ size_t spare_size;
njs_native_frame_t *frame;
- size = NJS_NATIVE_FRAME_SIZE + 3 * sizeof(njs_value_t);
+ spare_size = vm->frame->free_size;
- if (nxt_fast_path(size <= vm->frame->size)) {
- frame = (njs_native_frame_t *) vm->frame->last;
- frame->size = vm->frame->size - size;
- frame->start = 0;
+ if (nxt_fast_path(size <= spare_size)) {
+ frame = (njs_native_frame_t *) vm->frame->free;
+ frame->first = 0;
+ frame->skip = 0;
} else {
spare_size = size + NJS_FRAME_SPARE_SIZE;
frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
spare_size);
if (nxt_slow_path(frame == NULL)) {
- return NXT_ERROR;
+ return NULL;
}
- frame->size = spare_size - size;
- frame->start = 1;
+ frame->first = 1;
+ frame->skip = 0;
}
- frame->ctor = 0;
- frame->reentrant = 0;
-
- values = njs_native_data(frame);
- njs_set_invalid(&values[0]);
- values[2] = *value2;
-
- frame->trap_reference = njs_vm_traps[trap].reference_value;
+ frame->free_size = spare_size - size;
+ frame->free = (u_char *) frame + size;
- if (njs_vm_traps[trap].reference_value) {
- values[1].data.u.value = value1;
-
- } else {
- values[1] = *value1;
- }
+ frame->reentrant = 0;
+ frame->trap_reference = 0;
- frame->u.exception.catch = NULL;
- frame->u.restart = vm->current;
- vm->current = (u_char *) njs_vm_traps[trap].code;
+ frame->exception.next = NULL;
+ frame->exception.catch = NULL;
- frame->last = (u_char *) frame + size;
frame->previous = vm->frame;
vm->frame = frame;
- return NXT_OK;
+ return frame;
}
nxt_noinline njs_ret_t
njs_function_apply(njs_vm_t *vm, njs_value_t *name, njs_param_t *param)
{
- njs_ret_t ret;
+ njs_ret_t ret;
+ njs_function_t *function;
if (njs_is_native(name)) {
return name->data.u.method(vm, param);
} else if (njs_is_function(name)) {
- if (name->data.u.function->native) {
- return name->data.u.function->code.native(vm, param);
+ function = name->data.u.function;
+
+ if (function->native) {
+ return function->u.native(vm, param);
}
- ret = njs_vmcode_function_frame(vm, name, param, 0);
+ ret = njs_function_frame(vm, function, param, 0);
if (nxt_fast_path(ret == NXT_OK)) {
vm->retval = njs_value_void;
- return njs_function_call(vm, name->data.u.function, param->retval);
+ return njs_function_call(vm, param->retval);
}
}
nxt_noinline njs_ret_t
-njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *name, njs_param_t *param,
+njs_function_frame(njs_vm_t *vm, njs_function_t *function, njs_param_t *param,
nxt_bool_t ctor)
{
- size_t size, spare_size;
- uintptr_t nargs, n;
- njs_value_t *args, *arguments;
- njs_frame_t *frame;
- njs_function_t *func;
+ size_t size;
+ uintptr_t nargs, n;
+ njs_value_t *args, *arguments;
+ njs_frame_t *frame;
+ njs_native_frame_t *native_frame;
- func = name->data.u.function;
- nargs = nxt_max(param->nargs, func->code.script->nargs);
+ nargs = nxt_max(param->nargs, function->u.lambda->nargs);
size = NJS_FRAME_SIZE
+ nargs * sizeof(njs_value_t)
- + func->code.script->local_size;
- spare_size = size + func->code.script->spare_size;
-
- if (spare_size <= vm->frame->size) {
- frame = (njs_frame_t *) vm->frame->last;
- frame->native.size = vm->frame->size - size;
- frame->native.start = 0;
+ + function->u.lambda->local_size;
- } else {
- if (func->code.script->spare_size != 0) {
- spare_size = size + NJS_FRAME_SPARE_SIZE;
- spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE);
- }
-
- frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
- spare_size);
- if (nxt_slow_path(frame == NULL)) {
- return NXT_ERROR;
- }
-
- frame->native.size = spare_size - size;
- frame->native.start = 1;
+ native_frame = njs_function_frame_alloc(vm, size);
+ if (nxt_slow_path(native_frame == NULL)) {
+ return NXT_ERROR;
}
- frame->native.ctor = ctor;
- frame->native.reentrant = 0;
- frame->native.trap_reference = 0;
-
- frame->native.u.exception.next = NULL;
- frame->native.u.exception.catch = NULL;
+ native_frame->u.function = function;
+ native_frame->native = 0;
+ native_frame->ctor = ctor;
- frame->native.last = (u_char *) frame + size;
- frame->native.previous = vm->frame;
- vm->frame = &frame->native;
+ args = (njs_value_t *) ((u_char *) native_frame + NJS_FRAME_SIZE);
+ native_frame->arguments = args + function->args_offset;
+ vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = native_frame->arguments;
- args = (njs_value_t *) ((u_char *) frame + NJS_FRAME_SIZE);
- frame->native.arguments = args + func->args_offset;
- vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = frame->native.arguments;
+ frame = (njs_frame_t *) native_frame;
frame->local = &args[nargs];
nargs--;
}
- memcpy(frame->local, func->code.script->local_scope,
- func->code.script->local_size);
-
- vm->retval = *name;
+ memcpy(frame->local, function->u.lambda->local_scope,
+ function->u.lambda->local_size);
return NXT_OK;
}
nxt_noinline njs_ret_t
-njs_function_call(njs_vm_t *vm, njs_function_t *func, njs_index_t retval)
+njs_function_call(njs_vm_t *vm, njs_index_t retval)
{
- njs_frame_t *frame;
+ njs_frame_t *frame;
+ njs_function_t *function;
frame = (njs_frame_t *) vm->frame;
frame->retval = retval;
- frame->return_address = vm->current;
-
- vm->current = func->code.script->u.code;
+ function = frame->native.u.function;
+ frame->native.u.return_address = vm->current;
+ vm->current = function->u.lambda->u.start;
frame->prev_arguments = vm->scopes[NJS_SCOPE_ARGUMENTS];
vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->native.arguments
- - func->args_offset;
+ - function->args_offset;
#if (NXT_DEBUG)
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL;
#endif
static njs_ret_t
njs_function_prototype_call(njs_vm_t *vm, njs_param_t *param)
{
- uintptr_t nargs;
- njs_ret_t ret;
- njs_param_t p;
- njs_value_t *func;
- njs_vmcode_call_t *call;
+ uintptr_t nargs;
+ njs_ret_t ret;
+ njs_param_t p;
+ njs_value_t *func;
+ njs_function_t *function;
+ njs_vmcode_function_call_t *call;
p.object = ¶m->args[0];
p.args = ¶m->args[1];
return NXT_ERROR;
}
- if (func->data.u.function->native) {
+ function = func->data.u.function;
+
+ if (function->native) {
if (nargs != 0) {
p.nargs = nargs - 1;
p.retval = param->retval;
- return func->data.u.function->code.native(vm, &p);
+ return function->u.native(vm, &p);
}
vm->exception = &njs_exception_type_error;
p.nargs = nargs;
- ret = njs_vmcode_function_frame(vm, func, &p, 0);
+ ret = njs_function_frame(vm, function, &p, 0);
if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
/* Skip the "call" method frame. */
- vm->frame->previous = vm->frame->previous->previous;
+ vm->frame->previous->skip = 1;
- call = (njs_vmcode_call_t *) vm->current;
+ call = (njs_vmcode_function_call_t *) vm->current;
- return njs_function_call(vm, func->data.u.function, call->retval);
+ return njs_function_call(vm, call->retval);
}
static njs_ret_t
njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param)
{
- uintptr_t nargs;
- njs_ret_t ret;
- njs_param_t p;
- njs_array_t *array;
- njs_value_t *func, *args;
- njs_vmcode_call_t *code;
+ uintptr_t nargs;
+ njs_ret_t ret;
+ njs_param_t p;
+ njs_array_t *array;
+ njs_value_t *func, *args;
+ njs_function_t *function;
+ njs_vmcode_function_call_t *code;
args = param->args;
p.object = &args[0];
return func->data.u.method(vm, &p);
}
- if (func->data.u.function->native) {
+ function = func->data.u.function;
+
+ if (function->native) {
p.retval = param->retval;
if (nargs < 2) {
}
}
- return func->data.u.function->code.native(vm, &p);
+ return function->u.native(vm, &p);
}
if (nargs < 2) {
}
}
- ret = njs_vmcode_function_frame(vm, func, &p, 0);
+ ret = njs_function_frame(vm, function, &p, 0);
if (nxt_fast_path(ret == NXT_OK)) {
/* Skip the "apply" method frame. */
- vm->frame->previous = vm->frame->previous->previous;
+ vm->frame->previous->skip = 1;
- code = (njs_vmcode_call_t *) vm->current;
+ code = (njs_vmcode_function_call_t *) vm->current;
- return njs_function_call(vm, func->data.u.function, code->retval);
+ return njs_function_call(vm, code->retval);
}
return NXT_ERROR;
njs_value_t *func;
njs_function_t *bound;
- bound = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
- sizeof(njs_function_t));
+ bound = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_function_t));
if (nxt_fast_path(bound != NULL)) {
nxt_lvlhsh_init(&bound->object.hash);
bound->args_offset = 1;
func = param->object;
- bound->code.script = func->data.u.function->code.script;
+ bound->u.lambda = func->data.u.function->u.lambda;
vm->retval.data.u.function = bound;
vm->retval.type = NJS_FUNCTION;
#define _NJS_FUNCTION_H_INCLUDED_
-struct njs_function_script_s {
+struct njs_function_lambda_s {
uint32_t nargs;
uint32_t local_size;
- /*
- * Native methods do not allocate frame space so calling function
- * reserves space in its scope for method frame and arguments.
- */
- uint32_t spare_size;
/* Initial values of local scope. */
njs_value_t *local_scope;
union {
- u_char *code;
+ u_char *start;
njs_parser_t *parser;
} u;
};
struct njs_native_frame_s {
- u_char *last;
- njs_native_frame_t *previous;
- njs_value_t *arguments;
+ u_char *free;
+ /*
+ * The return_address is required in njs_frame_t only, however, it
+ * can be stored here just after function adddress has been fetched.
+ */
union {
+ njs_function_t *function;
+ u_char *return_address;
+ njs_native_t native;
u_char *restart;
- njs_exception_t exception;
} u;
- uint32_t size;
+ njs_native_frame_t *previous;
+ njs_value_t *arguments;
+
+ njs_exception_t exception;
+
+ uint32_t free_size;
+
+ /* Script or native function or method. */
+ uint8_t native; /* 1 bit */
- uint8_t start; /* 1 bit */
- uint8_t ctor; /* 1 bit */
- uint8_t reentrant; /* 1 bit */
- uint8_t trap_reference; /* 1 bit */
+ /* Function is called as constructor with "new" keyword. */
+ uint8_t ctor; /* 1 bit */
+
+ /*
+ * The first frame in chunk.
+ * 7 bits are just to possibly initialize first and skip
+ * fields with one operation.
+ */
+ uint8_t first:7; /* 1 bit */
+
+ /* Skip the Function.call() and Function.apply() methods frames. */
+ uint8_t skip:1; /* 1 bit */
+
+ /*
+ * The function is reentrant. It is usually used as a flag,
+ * however, in traps it used to allow just two entrances.
+ */
+ uint8_t reentrant:7; /* 2 bits */
+
+ /*
+ * The first operand in trap is reference to original value,
+ * it is used to increment or decrement this value.
+ */
+ uint8_t trap_reference:1;
};
njs_value_t *closure;
njs_index_t retval;
- u_char *return_address;
} njs_frame_t;
njs_function_t *njs_function_alloc(njs_vm_t *vm);
+njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size);
njs_ret_t njs_function_constructor(njs_vm_t *vm, njs_param_t *param);
njs_ret_t njs_function_apply(njs_vm_t *vm, njs_value_t *name,
njs_param_t *param);
-njs_value_t *njs_vmcode_native_frame(njs_vm_t *vm, njs_value_t *method,
- uintptr_t nargs, nxt_bool_t ctor);
-njs_ret_t njs_vmcode_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
- njs_value_t *value2);
-njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *name,
+njs_value_t *njs_function_native_frame(njs_vm_t *vm, njs_native_t native,
+ size_t local_size, njs_vmcode_t *code);
+njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function,
njs_param_t *param, nxt_bool_t ctor);
-njs_ret_t njs_function_call(njs_vm_t *vm, njs_function_t *func,
- njs_index_t retval);
+njs_ret_t njs_function_call(njs_vm_t *vm, njs_index_t retval);
extern const njs_object_init_t njs_function_constructor_init;
extern const njs_object_init_t njs_function_prototype_init;
njs_parser_t *parser, njs_parser_node_t *node);
static nxt_int_t njs_generate_inc_dec_operation(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node, nxt_bool_t post);
-static nxt_int_t njs_generate_function_statement(njs_vm_t *vm,
+static nxt_int_t njs_generate_function_declaration(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node);
static nxt_int_t njs_generate_return_statement(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node);
return NXT_ERROR;
- case NJS_TOKEN_OBJECT_LITERAL:
+ case NJS_TOKEN_OBJECT_VALUE:
node->index = node->u.object->index;
return NXT_OK;
- case NJS_TOKEN_OBJECT_CREATE:
+ case NJS_TOKEN_OBJECT:
return njs_generate_object(vm, parser, node);
- case NJS_TOKEN_ARRAY_CREATE:
+ case NJS_TOKEN_ARRAY:
return njs_generate_array(vm, parser, node);
- case NJS_TOKEN_FUNCTION_CREATE:
+ case NJS_TOKEN_FUNCTION_EXPRESSION:
return njs_generate_function(vm, parser, node);
- case NJS_TOKEN_REGEXP_LITERAL:
+ case NJS_TOKEN_REGEXP:
return njs_generate_regexp(vm, parser, node);
case NJS_TOKEN_THIS:
return njs_generate_variable(parser, node);
case NJS_TOKEN_FUNCTION:
- return njs_generate_function_statement(vm, parser, node);
+ return njs_generate_function_declaration(vm, parser, node);
case NJS_TOKEN_FUNCTION_CALL:
return njs_generate_function_call(vm, parser, node);
}
njs_generate_code(parser, njs_vmcode_object_t, obj);
- obj->code.operation = njs_vmcode_object_create;
+ obj->code.operation = njs_vmcode_object;
obj->code.operands = NJS_VMCODE_1OPERAND;
obj->code.retval = NJS_VMCODE_RETVAL;
obj->retval = index;
}
njs_generate_code(parser, njs_vmcode_array_t, array);
- array->code.operation = njs_vmcode_array_create;
+ array->code.operation = njs_vmcode_array;
array->code.operands = NJS_VMCODE_1OPERAND;
array->code.retval = NJS_VMCODE_RETVAL;
array->retval = index;
njs_generate_function(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
- njs_index_t index;
- njs_parser_node_t *body;
- njs_function_script_t *func;
- njs_vmcode_operation_t last;
- njs_vmcode_function_create_t *function;
-
- body = node->right;
-
- if (body != NULL
- && body->right != NULL
- && body->right->token == NJS_TOKEN_RETURN)
- {
- last = NULL;
-
- } else {
- last = njs_vmcode_return;
- }
+ nxt_int_t ret;
+ njs_index_t index;
+ njs_function_lambda_t *lambda;
+ njs_vmcode_function_t *function;
- func = node->u.value.data.u.data;
+ lambda = node->u.value.data.u.lambda;
- ret = njs_generate_scope(vm, func->u.parser, body, last);
+ ret = njs_generate_scope(vm, lambda->u.parser, node->right);
if (nxt_fast_path(ret == NXT_OK)) {
- func->local_size = func->u.parser->scope_size;
- func->spare_size = func->u.parser->method_arguments_size;
- func->local_scope = func->u.parser->local_scope;
- func->u.code = func->u.parser->code_start;
+ lambda->local_size = lambda->u.parser->scope_size;
+ lambda->local_scope = lambda->u.parser->local_scope;
+ lambda->u.start = lambda->u.parser->code_start;
/* Try to assign directly to variable. */
}
if (index == NJS_INDEX_NONE) {
+ node->temporary = 1;
index = njs_generator_temp_index_get(parser);
}
- njs_generate_code(parser, njs_vmcode_function_create_t, function);
- function->code.operation = njs_vmcode_function_create;
+ njs_generate_code(parser, njs_vmcode_function_t, function);
+ function->code.operation = njs_vmcode_function;
function->code.operands = NJS_VMCODE_1OPERAND;
function->code.retval = NJS_VMCODE_RETVAL;
function->retval = index;
- function->function = func;
+ function->lambda = lambda;
node->index = index;
}
njs_generate_code(parser, njs_vmcode_regexp_t, regexp);
- regexp->code.operation = njs_vmcode_regexp_create;
+ regexp->code.operation = njs_vmcode_regexp;
regexp->code.operands = NJS_VMCODE_1OPERAND;
regexp->code.retval = NJS_VMCODE_RETVAL;
regexp->retval = index;
static nxt_int_t
-njs_generate_function_statement(njs_vm_t *vm, njs_parser_t *parser,
+njs_generate_function_declaration(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
- njs_value_t *value;
- njs_function_t *func;
- njs_parser_node_t *body;
- njs_vmcode_operation_t last;
+ nxt_int_t ret;
+ njs_value_t *value;
+ njs_function_t *func;
value = njs_variable_value(parser, node->index);
func = value->data.u.function;
- body = node->right;
-
- if (body != NULL
- && body->right != NULL
- && body->right->token == NJS_TOKEN_RETURN)
- {
- last = NULL;
-
- } else {
- last = njs_vmcode_return;
- }
-
- ret = njs_generate_scope(vm, func->code.script->u.parser, body, last);
+ ret = njs_generate_scope(vm, func->u.lambda->u.parser, node->right);
if (nxt_fast_path(ret == NXT_OK)) {
- parser = func->code.script->u.parser;
+ parser = func->u.lambda->u.parser;
- func->code.script->local_size = parser->scope_size;
- func->code.script->spare_size = parser->method_arguments_size;
- func->code.script->local_scope = parser->local_scope;
- func->code.script->u.code = parser->code_start;
+ func->u.lambda->local_size = parser->scope_size;
+ func->u.lambda->local_scope = parser->local_scope;
+ func->u.lambda->u.start = parser->code_start;
node->u.value = *value;
}
nxt_int_t
-njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
- njs_vmcode_operation_t last)
+njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
{
size_t code_size, size;
u_char *p;
}
}
- if (last != NULL) {
+ if (parser->scope == NJS_SCOPE_GLOBAL) {
njs_generate_code(parser, njs_vmcode_stop_t, stop);
- stop->code.operation = last;
+ stop->code.operation = njs_vmcode_stop;
stop->code.operands = NJS_VMCODE_1OPERAND;
stop->code.retval = NJS_VMCODE_NO_RETVAL;
- index = njs_value_index(vm, parser, &njs_value_void);
-
- if (last == njs_vmcode_stop && node->index != 0) {
+ if (node->index != 0) {
index = node->index;
+
+ } else {
+ index = njs_value_index(vm, parser, &njs_value_void);
}
stop->retval = index;
njs_generate_return_statement(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
- njs_index_t index;
- njs_vmcode_stop_t *code;
+ nxt_int_t ret;
+ njs_index_t index;
+ njs_vmcode_return_t *code;
ret = njs_generator(vm, parser, node->right);
if (nxt_fast_path(ret == NXT_OK)) {
- njs_generate_code(parser, njs_vmcode_stop_t, code);
+ njs_generate_code(parser, njs_vmcode_return_t, code);
code->code.operation = njs_vmcode_return;
code->code.operands = NJS_VMCODE_1OPERAND;
code->code.retval = NJS_VMCODE_NO_RETVAL;
njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- uintptr_t nargs;
- nxt_int_t ret;
- njs_index_t retval, index, name;
- njs_parser_node_t *arg;
- njs_vmcode_call_t *call;
- njs_vmcode_move_t *move;
- njs_vmcode_function_t *func;
+ uintptr_t nargs;
+ nxt_int_t ret;
+ njs_index_t retval;
+ njs_parser_node_t *arg, *name;
+ njs_vmcode_move_t *move;
+ njs_vmcode_function_call_t *call;
+ njs_vmcode_function_frame_t *func;
if (node->left != NULL) {
/* Generate function code in function expression. */
return ret;
}
- name = node->left->index;
+ name = node->left;
} else {
/* njs_generate_variable() always returns NXT_OK. */
(void) njs_generate_variable(parser, node);
- name = node->index;
+ name = node;
}
- njs_generate_code(parser, njs_vmcode_function_t, func);
- func->code.operation = njs_vmcode_function;
- func->code.operands = NJS_VMCODE_2OPERANDS;
- func->code.retval = NJS_VMCODE_RETVAL;
+ njs_generate_code(parser, njs_vmcode_function_frame_t, func);
+ func->code.operation = njs_vmcode_function_frame;
+ func->code.operands = NJS_VMCODE_1OPERAND;
+ func->code.retval = NJS_VMCODE_NO_RETVAL;
func->code.ctor = node->ctor;
- func->name = name;
+ func->name = name->index;
- index = njs_generator_temp_index_get(parser);
- func->function = index;
+ ret = njs_generator_node_index_release(vm, parser, name);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
nargs = 1;
if (retval == NJS_INDEX_NONE) {
node->temporary = 1;
- retval = index;
+ retval = njs_generator_temp_index_get(parser);
}
node->index = retval;
- njs_generate_code(parser, njs_vmcode_call_t, call);
- call->code.operation = njs_vmcode_call;
- call->code.operands = NJS_VMCODE_2OPERANDS;
+ njs_generate_code(parser, njs_vmcode_function_call_t, call);
+ call->code.operation = njs_vmcode_function_call;
+ call->code.operands = NJS_VMCODE_1OPERAND;
call->code.retval = NJS_VMCODE_NO_RETVAL;
call->code.nargs = nargs;
- call->function = index;
call->retval = retval;
- if (retval == index) {
- return NXT_OK;
- }
-
- return njs_generator_index_release(vm, parser, index);
+ return NXT_OK;
}
njs_generate_method_call(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- uintptr_t nargs;
- nxt_int_t ret;
- njs_index_t retval, index;
- njs_parser_node_t *arg, *prop;
- njs_vmcode_call_t *call;
- njs_vmcode_move_t *move;
- njs_vmcode_method_t *method;
+ uintptr_t nargs;
+ nxt_int_t ret;
+ njs_index_t retval;
+ njs_parser_node_t *arg, *prop;
+ njs_vmcode_move_t *move;
+ njs_vmcode_method_frame_t *method;
+ njs_vmcode_function_call_t *call;
prop = node->left;
return ret;
}
- if (prop->left->temporary) {
- index = prop->left->index;
-
- ret = njs_generator_node_index_release(vm, parser, prop->right);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- } else if (prop->right->temporary) {
- index = prop->right->index;
-
- } else {
- index = njs_generator_temp_index_get(parser);
- }
-
- njs_generate_code(parser, njs_vmcode_method_t, method);
- method->code.operation = njs_vmcode_method;
- method->code.operands = NJS_VMCODE_3OPERANDS;
- method->code.retval = NJS_VMCODE_RETVAL;
+ njs_generate_code(parser, njs_vmcode_method_frame_t, method);
+ method->code.operation = njs_vmcode_method_frame;
+ method->code.operands = NJS_VMCODE_2OPERANDS;
+ method->code.retval = NJS_VMCODE_NO_RETVAL;
method->code.ctor = node->ctor;
- method->function = index;
method->object = prop->left->index;
method->method = prop->right->index;
+ ret = njs_generator_children_indexes_release(vm, parser, prop);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
nargs = 1;
for (arg = node->right; arg != NULL; arg = arg->right) {
if (retval == NJS_INDEX_NONE) {
node->temporary = 1;
- retval = index;
+ retval = njs_generator_temp_index_get(parser);
}
node->index = retval;
- njs_generate_code(parser, njs_vmcode_call_t, call);
- call->code.operation = njs_vmcode_call;
- call->code.operands = NJS_VMCODE_2OPERANDS;
+ njs_generate_code(parser, njs_vmcode_function_call_t, call);
+ call->code.operation = njs_vmcode_function_call;
+ call->code.operands = NJS_VMCODE_1OPERAND;
call->code.retval = NJS_VMCODE_NO_RETVAL;
call->code.nargs = nargs;
- call->function = index;
call->retval = retval;
- if (retval == index) {
- return NXT_OK;
- }
-
- return njs_generator_index_release(vm, parser, index);
+ return NXT_OK;
}
static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser,
njs_token_t token);
static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser);
-static njs_token_t njs_parser_function_statement(njs_vm_t *vm,
+static njs_token_t njs_parser_function_declaration(njs_vm_t *vm,
njs_parser_t *parser);
+static njs_parser_t *njs_parser_function_create(njs_vm_t *vm,
+ njs_parser_t *parent);
+static njs_token_t njs_parser_function_lambda(njs_vm_t *vm,
+ njs_function_lambda_t *lambda, njs_token_t token);
static njs_token_t njs_parser_return_statement(njs_vm_t *vm,
njs_parser_t *parser);
static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser);
switch (token) {
case NJS_TOKEN_FUNCTION:
- return njs_parser_function_statement(vm, parser);
+ return njs_parser_function_declaration(vm, parser);
case NJS_TOKEN_RETURN:
return njs_parser_return_statement(vm, parser);
static njs_token_t
-njs_parser_function_statement(njs_vm_t *vm, njs_parser_t *parser)
+njs_parser_function_declaration(njs_vm_t *vm, njs_parser_t *parser)
{
- nxt_str_t *name;
nxt_uint_t level;
- njs_index_t index;
- njs_value_t *value;
njs_token_t token;
- njs_parser_t *fn_parser;
- njs_variable_t *arg, *var;
+ njs_value_t *value;
+ njs_variable_t *var;
+ njs_function_t *function;
njs_parser_node_t *node;
node = njs_parser_node_alloc(vm);
return token;
}
- if (token == NJS_TOKEN_NAME) {
- nxt_thread_log_debug("function: %V", &parser->lexer->text);
-
- var = njs_parser_variable(vm, parser, &level);
- if (nxt_slow_path(var == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- var->state = NJS_VARIABLE_DECLARED;
-
- token = njs_parser_token(parser);
- if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
- }
-
- index = var->index;
- value = njs_variable_value(parser, index);
-
- } else {
- /* Anonymous function. */
- value = nxt_array_add(parser->scope_values, &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(value == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- index = njs_parser_index(parser, parser->scope);
- }
-
- value->type = NJS_FUNCTION;
- node->index = index;
-
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
- if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
- }
-
- value->data.u.function = njs_function_alloc(vm);
- if (nxt_slow_path(value->data.u.function == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- fn_parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
- if (nxt_slow_path(fn_parser == NULL)) {
+ if (token != NJS_TOKEN_NAME) {
return NJS_TOKEN_ERROR;
}
- value->data.u.function->code.script->u.parser = fn_parser;
-
- fn_parser->lexer = parser->lexer;
-
- /* njs_vmcode_return() size. */
- fn_parser->code_size = sizeof(njs_vmcode_stop_t);
-
- fn_parser->arguments = nxt_array_create(4, sizeof(njs_variable_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(fn_parser->arguments == NULL)) {
+ var = njs_parser_variable(vm, parser, &level);
+ if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- fn_parser->parent = parser;
-
- vm->parser = fn_parser;
-
- index = NJS_SCOPE_ARGUMENTS;
-
- /* A "this" reservation. */
- index += sizeof(njs_value_t);
-
- while (token != NJS_TOKEN_CLOSE_PARENTHESIS) {
-
- if (nxt_slow_path(token != NJS_TOKEN_NAME)) {
- return NJS_TOKEN_ERROR;
- }
-
- name = &fn_parser->lexer->text;
-
- nxt_thread_log_debug("arg: %V", name);
-
- arg = nxt_array_add(fn_parser->arguments, &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(arg == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len);
- if (nxt_slow_path(arg->name_start == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- memcpy(arg->name_start, name->data, name->len);
- arg->name_len = name->len;
-
- arg->state = NJS_VARIABLE_DECLARED;
- arg->index = index;
- index += sizeof(njs_value_t);
-
- token = njs_parser_token(fn_parser);
- if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
- }
-
- if (token == NJS_TOKEN_COMMA) {
- token = njs_parser_token(fn_parser);
- if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
- }
- }
- }
+ var->state = NJS_VARIABLE_DECLARED;
+ node->index = var->index;
- value->data.u.function->code.script->nargs =
- njs_index_size(index) / sizeof(njs_value_t);
-
- token = njs_parser_token(fn_parser);
+ token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
- if (nxt_slow_path(token != NJS_TOKEN_OPEN_BRACE)) {
- return NJS_TOKEN_ERROR;
- }
+ parser->node = node;
- fn_parser->scope_values = nxt_array_create(4, sizeof(njs_value_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(fn_parser->scope_values == NULL)) {
- return NXT_ERROR;
+ function = njs_function_alloc(vm);
+ if (nxt_slow_path(function == NULL)) {
+ return NJS_TOKEN_ERROR;
}
- fn_parser->scope = NJS_SCOPE_LOCAL;
-
- token = njs_parser_block(vm, fn_parser);
+ value = njs_variable_value(parser, node->index);
+ value->data.u.function = function;
+ value->type = NJS_FUNCTION;
- vm->parser = parser;
- node->right = fn_parser->node;
+ parser = njs_parser_function_create(vm, parser);
+ if (nxt_slow_path(parser == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
- parser->node = node;
+ function->u.lambda->u.parser = parser;
- return token;
+ return njs_parser_function_lambda(vm, function->u.lambda, token);
}
static njs_token_t
njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
{
- nxt_str_t *name;
nxt_uint_t level;
+ njs_token_t token;
njs_index_t index;
njs_value_t *value;
- njs_token_t token;
- njs_parser_t *fn_parser;
- njs_variable_t *arg, *var;
+ njs_variable_t *var;
+ njs_function_t *function;
njs_parser_node_t *node;
- njs_function_script_t *func;
+ njs_function_lambda_t *lambda;
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
return NJS_TOKEN_ERROR;
}
- node->token = NJS_TOKEN_FUNCTION_CREATE;
+ node->token = NJS_TOKEN_FUNCTION_EXPRESSION;
+ parser->node = node;
+ parser->code_size += sizeof(njs_vmcode_function_t);
+
+ parser = njs_parser_function_create(vm, parser);
+ if (nxt_slow_path(parser == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
}
if (token == NJS_TOKEN_NAME) {
- nxt_thread_log_debug("function: %V", &parser->lexer->text);
-
var = njs_parser_variable(vm, parser, &level);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
+ var->state = NJS_VARIABLE_DECLARED;
+
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
+
+ index = var->index;
+ value = njs_variable_value(parser, index);
+
+ function = njs_function_alloc(vm);
+ if (nxt_slow_path(function == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ value->data.u.function = function;
+ value->type = NJS_FUNCTION;
+ lambda = function->u.lambda;
+
+ } else {
+ /* Anonymous function. */
+ lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+ sizeof(njs_function_lambda_t));
+ if (nxt_slow_path(lambda == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
}
- value = &node->u.value;
+ node->u.value.data.u.lambda = lambda;
+ lambda->u.parser = parser;
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
- if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
+ return njs_parser_function_lambda(vm, lambda, token);
+}
+
+
+static njs_parser_t *
+njs_parser_function_create(njs_vm_t *vm, njs_parser_t *parent)
+{
+ nxt_array_t *values, *arguments;
+ njs_parser_t *parser;
+
+ parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
+ if (nxt_slow_path(parser == NULL)) {
+ return NULL;
}
- func = nxt_mem_cache_zalloc(vm->mem_cache_pool,
- sizeof(njs_function_script_t));
- if (nxt_slow_path(func == NULL)) {
- return NJS_TOKEN_ERROR;
+ parser->parent = parent;
+ parser->lexer = parent->lexer;
+ vm->parser = parser;
+
+ arguments = nxt_array_create(4, sizeof(njs_variable_t),
+ &njs_array_mem_proto, vm->mem_cache_pool);
+ if (nxt_slow_path(arguments == NULL)) {
+ return NULL;
}
- value->data.u.data = func;
+ parser->arguments = arguments;
- fn_parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
- if (nxt_slow_path(fn_parser == NULL)) {
- return NJS_TOKEN_ERROR;
+ values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
+ vm->mem_cache_pool);
+ if (nxt_slow_path(values == NULL)) {
+ return NULL;
}
- func->u.parser = fn_parser;
+ parser->scope_values = values;
+ parser->scope = NJS_SCOPE_LOCAL;
- fn_parser->lexer = parser->lexer;
+ return parser;
+}
- /* njs_vmcode_return() size. */
- fn_parser->code_size = sizeof(njs_vmcode_stop_t);
- fn_parser->arguments = nxt_array_create(4, sizeof(njs_variable_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(fn_parser->arguments == NULL)) {
- return NJS_TOKEN_ERROR;
- }
+static njs_token_t
+njs_parser_function_lambda(njs_vm_t *vm, njs_function_lambda_t *lambda,
+ njs_token_t token)
+{
+ nxt_str_t *name;
+ njs_index_t index;
+ njs_parser_t *parser;
+ njs_variable_t *arg;
+ njs_parser_node_t *node, *body;
- fn_parser->parent = parser;
+ parser = lambda->u.parser;
- vm->parser = fn_parser;
+ token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
index = NJS_SCOPE_ARGUMENTS;
return NJS_TOKEN_ERROR;
}
- name = &fn_parser->lexer->text;
-
- nxt_thread_log_debug("arg: %V", name);
-
- arg = nxt_array_add(fn_parser->arguments, &njs_array_mem_proto,
+ arg = nxt_array_add(parser->arguments, &njs_array_mem_proto,
vm->mem_cache_pool);
if (nxt_slow_path(arg == NULL)) {
return NJS_TOKEN_ERROR;
}
+ name = &parser->lexer->text;
+
arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len);
if (nxt_slow_path(arg->name_start == NULL)) {
return NJS_TOKEN_ERROR;
arg->index = index;
index += sizeof(njs_value_t);
- token = njs_parser_token(fn_parser);
+ token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
if (token == NJS_TOKEN_COMMA) {
- token = njs_parser_token(fn_parser);
+ token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
}
}
- func->nargs = njs_index_size(index) / sizeof(njs_value_t);
+ lambda->nargs = njs_index_size(index) / sizeof(njs_value_t);
- token = njs_parser_token(fn_parser);
+ token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
return NJS_TOKEN_ERROR;
}
- fn_parser->scope_values = nxt_array_create(4, sizeof(njs_value_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(fn_parser->scope_values == NULL)) {
- return NXT_ERROR;
+ token = njs_parser_block(vm, parser);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
}
- fn_parser->scope = NJS_SCOPE_LOCAL;
+ /*
+ * There is no function body or the last function body statement is not
+ * "return" statement. If function has body then the body->right node is
+ * always present and it is a NJS_TOKEN_STATEMENT link node.
+ */
+ body = parser->node;
- token = njs_parser_block(vm, fn_parser);
+ if (body == NULL || body->right->token != NJS_TOKEN_RETURN) {
+ node = njs_parser_node_alloc(vm);
+ if (nxt_slow_path(node == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
- vm->parser = parser;
- node->right = fn_parser->node;
+ node->token = NJS_TOKEN_STATEMENT;
+ node->left = parser->node;
+ parser->node = node;
- parser->node = node;
- parser->code_size += sizeof(njs_vmcode_function_create_t);
+ node->right = njs_parser_node_alloc(vm);
+ if (nxt_slow_path(node->right == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ node->right->token = NJS_TOKEN_RETURN;
+
+ parser->code_size += sizeof(njs_vmcode_return_t);
+ }
+
+ parser->parent->node->right = parser->node;
+ vm->parser = parser->parent;
return token;
}
node->token = NJS_TOKEN_RETURN;
parser->node = node;
- parser->code_size += sizeof(njs_vmcode_stop_t);
+ parser->code_size += sizeof(njs_vmcode_return_t);
token = njs_lexer_token(parser->lexer);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
break;
case NJS_TOKEN_OPEN_BRACE:
- node->token = NJS_TOKEN_OBJECT_CREATE;
+ node->token = NJS_TOKEN_OBJECT;
nxt_thread_log_debug("JS: OBJECT");
return token;
case NJS_TOKEN_OPEN_BRACKET:
- node->token = NJS_TOKEN_ARRAY_CREATE;
+ node->token = NJS_TOKEN_ARRAY;
nxt_thread_log_debug("JS: ARRAY");
nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text);
- node->token = NJS_TOKEN_REGEXP_LITERAL;
+ node->token = NJS_TOKEN_REGEXP;
parser->code_size += sizeof(njs_vmcode_regexp_t);
break;
return NJS_TOKEN_ERROR;
}
- object->token = NJS_TOKEN_OBJECT_LITERAL;
+ object->token = NJS_TOKEN_OBJECT_VALUE;
object->u.object = obj;
propref = njs_parser_node_alloc(vm);
return NJS_TOKEN_ERROR;
}
- object->token = NJS_TOKEN_OBJECT_LITERAL;
+ object->token = NJS_TOKEN_OBJECT_VALUE;
object->u.object = obj;
propref = njs_parser_node_alloc(vm);
NJS_TOKEN_ESCAPE_STRING,
NJS_TOKEN_NAME,
- NJS_TOKEN_OBJECT_CREATE,
- NJS_TOKEN_OBJECT_LITERAL,
+ NJS_TOKEN_OBJECT,
+ NJS_TOKEN_OBJECT_VALUE,
NJS_TOKEN_PROPERTY,
NJS_TOKEN_PROPERTY_DELETE,
- NJS_TOKEN_ARRAY_CREATE,
+ NJS_TOKEN_ARRAY,
- NJS_TOKEN_FUNCTION_CREATE,
NJS_TOKEN_FUNCTION,
+ NJS_TOKEN_FUNCTION_EXPRESSION,
NJS_TOKEN_FUNCTION_CALL,
NJS_TOKEN_METHOD_CALL,
NJS_TOKEN_ARGUMENT,
NJS_TOKEN_RETURN,
- NJS_TOKEN_REGEXP_LITERAL,
+ NJS_TOKEN_REGEXP,
NJS_TOKEN_EXTERNAL,
size_t scope_size;
size_t scope_offset;
- uint32_t nesting_arguments;
- uint32_t nesting_arguments_size;
- uint32_t method_arguments_size;
-
u_char *code_start;
u_char *code_end;
njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope);
nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *node, njs_vmcode_operation_t last);
+ njs_parser_node_t *node);
#define njs_generate_code(parser, type, code) \
case NJS_TOKEN_NAME:
func = node;
func->token = NJS_TOKEN_FUNCTION_CALL;
- parser->code_size += sizeof(njs_vmcode_function_t)
- + sizeof(njs_vmcode_call_t);
+ parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ + sizeof(njs_vmcode_function_call_t);
break;
- case NJS_TOKEN_FUNCTION_CREATE:
+ case NJS_TOKEN_FUNCTION_EXPRESSION:
func = njs_parser_node_alloc(vm);
if (nxt_slow_path(func == NULL)) {
return NJS_TOKEN_ERROR;
func->token = NJS_TOKEN_FUNCTION_CALL;
func->left = node;
func->index = node->index;
- parser->code_size += sizeof(njs_vmcode_function_t)
- + sizeof(njs_vmcode_call_t);
+ parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ + sizeof(njs_vmcode_function_call_t);
break;
- case NJS_TOKEN_OBJECT_CONSTRUCTOR:
- case NJS_TOKEN_ARRAY_CONSTRUCTOR:
- case NJS_TOKEN_BOOLEAN_CONSTRUCTOR:
- case NJS_TOKEN_NUMBER_CONSTRUCTOR:
- case NJS_TOKEN_STRING_CONSTRUCTOR:
- case NJS_TOKEN_FUNCTION_CONSTRUCTOR:
- case NJS_TOKEN_REGEXP_CONSTRUCTOR:
- case NJS_TOKEN_EVAL:
+ case NJS_TOKEN_PROPERTY:
func = njs_parser_node_alloc(vm);
if (nxt_slow_path(func == NULL)) {
return NJS_TOKEN_ERROR;
}
- func->token = NJS_TOKEN_FUNCTION_CALL;
+ func->token = NJS_TOKEN_METHOD_CALL;
func->left = node;
- parser->code_size += sizeof(njs_vmcode_method_t)
- + sizeof(njs_vmcode_call_t);
+ parser->code_size += sizeof(njs_vmcode_method_frame_t)
+ + sizeof(njs_vmcode_function_call_t);
break;
default:
+ /*
+ * NJS_TOKEN_OPEN_PARENTHESIS,
+ * NJS_TOKEN_OBJECT_CONSTRUCTOR,
+ * NJS_TOKEN_ARRAY_CONSTRUCTOR,
+ * NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
+ * NJS_TOKEN_NUMBER_CONSTRUCTOR,
+ * NJS_TOKEN_STRING_CONSTRUCTOR,
+ * NJS_TOKEN_FUNCTION_CONSTRUCTOR,
+ * NJS_TOKEN_REGEXP_CONSTRUCTOR,
+ * NJS_TOKEN_EVAL.
+ */
func = njs_parser_node_alloc(vm);
if (nxt_slow_path(func == NULL)) {
return NJS_TOKEN_ERROR;
}
- func->token = NJS_TOKEN_METHOD_CALL;
+ func->token = NJS_TOKEN_FUNCTION_CALL;
func->left = node;
- parser->code_size += sizeof(njs_vmcode_method_t)
- + sizeof(njs_vmcode_call_t);
+ parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ + sizeof(njs_vmcode_function_call_t);
+ break;
}
token = njs_parser_arguments(vm, parser, func);
njs_index_t index;
njs_parser_node_t *node;
- parser->nesting_arguments++;
index = NJS_SCOPE_CALLEE_ARGUMENTS;
do {
return NJS_TOKEN_ILLEGAL;
}
- index = njs_index_size(index);
- index += NJS_NATIVE_FRAME_SIZE + sizeof(njs_value_t);
-
- parser->nesting_arguments_size += index;
-
- parser->nesting_arguments--;
-
- if (parser->nesting_arguments == 0) {
-
- if (parser->method_arguments_size < parser->nesting_arguments_size) {
- parser->method_arguments_size = parser->nesting_arguments_size;
- }
-
- parser->nesting_arguments_size = 0;
- }
-
return token;
}
njs_value_t *val2);
static nxt_noinline nxt_bool_t njs_values_strict_equal(njs_value_t *val1,
njs_value_t *val2);
+static nxt_noinline njs_ret_t njs_function_frame_free(njs_vm_t *vm,
+ njs_native_frame_t *frame, njs_native_frame_t *skip);
+
+static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *narg);
+static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *narg);
static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value,
nxt_uint_t hint);
+static njs_ret_t njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
+ njs_value_t *value2);
+static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *invld2);
+
void njs_debug(njs_index_t index, njs_value_t *value);
* njs_vmcode_if_true_jump(),
* njs_vmcode_if_false_jump(),
* njs_vmcode_validate(),
- * njs_vmcode_call(),
+ * njs_vmcode_function_frame(),
+ * njs_vmcode_method_frame(),
+ * njs_vmcode_function_call(),
* njs_vmcode_return(),
* njs_vmcode_try_start(),
* njs_vmcode_try_next(),
case NJS_TRAP_INCDEC:
case NJS_TRAP_PROPERTY:
- ret = njs_vmcode_trap(vm, ret - NJS_TRAP_LAST, value1, value2);
+ ret = njs_vm_trap(vm, ret - NJS_TRAP_LAST, value1, value2);
if (nxt_fast_path(ret == NXT_OK)) {
goto again;
for ( ;; ) {
frame = (njs_frame_t *) vm->frame;
- catch = frame->native.u.exception.catch;
+ catch = frame->native.exception.catch;
if (catch != NULL) {
vm->current = catch;
vm->scopes[NJS_SCOPE_LOCAL] = frame->prev_local;
vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->prev_arguments;
- if (frame->native.start) {
+ if (frame->native.first) {
nxt_mem_cache_free(vm->mem_cache_pool, frame);
}
}
njs_ret_t
-njs_vmcode_object_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_object(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
{
njs_object_t *object;
njs_ret_t
-njs_vmcode_array_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_array(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
{
uint32_t size;
njs_array_t *array;
njs_ret_t
-njs_vmcode_function_create(njs_vm_t *vm, njs_value_t *invld1,
+njs_vmcode_function(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *invld2)
{
- njs_function_t *func;
- njs_vmcode_function_create_t *code;
+ njs_function_t *function;
+ njs_vmcode_function_t *code;
- func = nxt_mem_cache_zalign(vm->mem_cache_pool, sizeof(njs_value_t),
- sizeof(njs_function_t));
+ function = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
- if (nxt_fast_path(func != NULL)) {
- func->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
- func->args_offset = 1;
+ if (nxt_fast_path(function != NULL)) {
+ function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
+ function->args_offset = 1;
- code = (njs_vmcode_function_create_t *) vm->current;
- func->code.script = code->function;
- vm->retval.data.u.function = func;
+ code = (njs_vmcode_function_t *) vm->current;
+ function->u.lambda = code->lambda;
+ vm->retval.data.u.function = function;
vm->retval.type = NJS_FUNCTION;
vm->retval.data.truth = 1;
- return sizeof(njs_vmcode_function_create_t);
+ return sizeof(njs_vmcode_function_t);
}
return NXT_ERROR;
njs_ret_t
-njs_vmcode_regexp_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
{
njs_regexp_t *regexp;
njs_vmcode_regexp_t *code;
njs_ret_t
-njs_vmcode_function(njs_vm_t *vm, njs_value_t *name, njs_value_t *invld)
+njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *invld, njs_value_t *name)
{
- njs_ret_t ret;
- njs_value_t value, *this;
- njs_param_t param;
- njs_object_t *object;
- njs_function_t *function;
- njs_vmcode_function_t *func;
+ njs_ret_t ret;
+ njs_value_t val, *this, *value;
+ njs_param_t param;
+ njs_object_t *object;
+ njs_function_t *function;
+ njs_vmcode_function_frame_t *func;
+
+ value = njs_vmcode_operand(vm, name);
- if (nxt_fast_path(njs_is_function(name))) {
+ if (nxt_fast_path(njs_is_function(value))) {
- func = (njs_vmcode_function_t *) vm->current;
+ func = (njs_vmcode_function_frame_t *) vm->current;
- function = name->data.u.function;
+ function = value->data.u.function;
if (function->native) {
- this = njs_vmcode_native_frame(vm, &vm->retval, func->code.nargs,
- func->code.ctor);
+ this = njs_function_native_frame(vm, function->u.native, 0,
+ &func->code);
if (nxt_fast_path(this != NULL)) {
*this = njs_value_void;
- vm->retval = *name;
- return sizeof(njs_vmcode_function_t);
+ return sizeof(njs_vmcode_function_frame_t);
}
return NXT_ERROR;
return NXT_ERROR;
}
- value.data.u.object = object;
- value.type = NJS_OBJECT;
- value.data.truth = 1;
- param.object = &value;
+ val.data.u.object = object;
+ val.type = NJS_OBJECT;
+ val.data.truth = 1;
+ param.object = &val;
} else {
param.object = (njs_value_t *) &njs_value_void;
param.args = NULL;
param.nargs = func->code.nargs;
- ret = njs_vmcode_function_frame(vm, name, ¶m, func->code.ctor);
+ ret = njs_function_frame(vm, function, ¶m, func->code.ctor);
if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_function_t);
+ return sizeof(njs_vmcode_function_frame_t);
}
- } else {
- vm->exception = &njs_exception_type_error;
+ return ret;
}
+ vm->exception = &njs_exception_type_error;
+
return NXT_ERROR;
}
njs_ret_t
-njs_vmcode_method(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
+njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *name, njs_value_t *object)
{
- uintptr_t nargs;
- njs_ret_t ret;
- njs_value_t *this;
- njs_param_t param;
- njs_extern_t *ext;
- njs_object_prop_t *prop;
- njs_vmcode_method_t *method;
- njs_property_query_t pq;
+ njs_ret_t ret;
+ njs_value_t *this;
+ njs_param_t param;
+ njs_extern_t *ext;
+ njs_function_t *function;
+ njs_object_prop_t *prop;
+ njs_property_query_t pq;
+ njs_vmcode_method_frame_t *method;
- method = (njs_vmcode_method_t *) vm->current;
- nargs = method->code.nargs;
+ object = njs_vmcode_operand(vm, object);
pq.query = NJS_PROPERTY_QUERY_GET;
case NXT_OK:
prop = pq.lhq.value;
- if (njs_is_function(&prop->value)
- && !prop->value.data.u.function->native)
- {
- param.object = object;
- param.args = NULL;
- param.nargs = nargs;
+ if (njs_is_function(&prop->value)) {
- ret = njs_vmcode_function_frame(vm, &prop->value, ¶m,
- method->code.ctor);
+ method = (njs_vmcode_method_frame_t *) vm->current;
+ function = prop->value.data.u.function;
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_method_t);
- }
+ if (!function->native) {
+ param.object = object;
+ param.args = NULL;
+ param.nargs = method->code.nargs;
- return ret;
- }
+ ret = njs_function_frame(vm, function, ¶m,
+ method->code.ctor);
+
+ if (nxt_fast_path(ret == NXT_OK)) {
+ return sizeof(njs_vmcode_method_frame_t);
+ }
+
+ return ret;
+ }
- vm->retval = prop->value;
+ this = njs_function_native_frame(vm, function->u.native,
+ prop->value.data.string_size,
+ &method->code);
+ if (nxt_slow_path(this == NULL)) {
+ return NXT_ERROR;
+ }
- njs_retain(object);
+ njs_retain(object);
+ *this = *object;
- this = njs_vmcode_native_frame(vm, &vm->retval, nargs,
- method->code.ctor);
- if (nxt_slow_path(this == NULL)) {
- return NXT_ERROR;
+ return sizeof(njs_vmcode_method_frame_t);
}
- *this = *object;
-
- return sizeof(njs_vmcode_method_t);
+ break;
case NJS_EXTERNAL_VALUE:
ext = object->data.u.external;
ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
if (ret == NXT_OK) {
+ method = (njs_vmcode_method_frame_t *) vm->current;
ext = pq.lhq.value;
if (ext->type == NJS_EXTERN_METHOD) {
- vm->retval.type = NJS_NATIVE;
- vm->retval.data.truth = 1;
- vm->retval.data.string_size = 0;
- vm->retval.data.u.method = ext->method;
-
- this = njs_vmcode_native_frame(vm, &vm->retval, nargs,
- method->code.ctor);
+ this = njs_function_native_frame(vm, ext->method, 0,
+ &method->code);
if (nxt_slow_path(this == NULL)) {
return NXT_ERROR;
this->data.u.data = vm->external[ext->object];
- return sizeof(njs_vmcode_method_t);
+ return sizeof(njs_vmcode_method_frame_t);
}
}
- /* Fall through. */
+ break;
default:
- vm->exception = &njs_exception_type_error;
- return NXT_ERROR;
+ break;
}
+
+ vm->exception = &njs_exception_type_error;
+
+ return NXT_ERROR;
}
njs_ret_t
-njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval)
+njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
{
- njs_ret_t ret;
- njs_value_t *args;
- njs_param_t param;
- njs_native_t native;
- njs_function_t *function;
- njs_vmcode_call_t *call;
-
- call = (njs_vmcode_call_t *) vm->current;
- vm->current += sizeof(njs_vmcode_call_t);
+ njs_ret_t ret;
+ njs_value_t *args;
+ njs_param_t param;
+ njs_native_frame_t *frame, *previous, *skip;
+ njs_vmcode_function_call_t *call;
- if (njs_is_function(func)) {
- function = func->data.u.function;
+ call = (njs_vmcode_function_call_t *) vm->current;
+ vm->current += sizeof(njs_vmcode_function_call_t);
- if (!function->native) {
- (void) njs_function_call(vm, function, (njs_index_t) retval);
- return 0;
- }
-
- native = function->code.native;
-
- } else {
- native = func->data.u.method;
+ if (!vm->frame->native) {
+ (void) njs_function_call(vm, (njs_index_t) retval);
+ return 0;
}
param.retval = (njs_index_t) retval;
param.args = args;
param.object = args - 1;
- ret = native(vm, ¶m);
+ ret = vm->frame->u.native(vm, ¶m);
/*
* A native method can return:
* NXT_OK on method success;
* The callee arguments must be preserved for NJS_PASS and NXT_AGAIN cases.
*/
if (ret == NXT_OK) {
+ skip = NULL;
+ frame = vm->frame;
+ previous = frame->previous;
+
+ if (previous->skip) {
+
+ if (previous->first) {
+ skip = previous;
+ }
+
+ previous = previous->previous;
+ }
+
+ vm->frame = previous;
+
+ (void) njs_function_frame_free(vm, frame, skip);
+
/*
* If a retval is in a callee arguments scope it
* must be in the previous callee arguments scope.
*/
- vm->frame = vm->frame->previous;
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = vm->frame->arguments;
retval = njs_vmcode_operand(vm, retval);
njs_value_t *value;
njs_frame_t *frame;
njs_value_t *args;
- njs_native_frame_t *previous;
+ njs_native_frame_t *previous, *skip;
value = njs_vmcode_operand(vm, retval);
}
}
+ skip = NULL;
previous = frame->native.previous;
+
+ if (previous->skip) {
+
+ if (previous->first) {
+ skip = previous;
+ }
+
+ previous = previous->previous;
+ }
+
vm->frame = previous;
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = previous->arguments;
/* GC: value external/internal++ depending on value and retval type */
*retval = *value;
- vm->current = frame->return_address;
+ vm->current = frame->native.u.return_address;
/* GC: arguments and local. */
njs_release(vm, &args[0]);
- if (frame->native.start) {
+ return njs_function_frame_free(vm, &frame->native, skip);
+}
+
+
+static nxt_noinline njs_ret_t
+njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame,
+ njs_native_frame_t *skip)
+{
+ if (frame->first) {
nxt_mem_cache_free(vm->mem_cache_pool, frame);
}
+ if (skip != NULL) {
+ nxt_mem_cache_free(vm->mem_cache_pool, skip);
+ }
+
return 0;
}
{
njs_exception_t *e;
- if (vm->frame->u.exception.catch != NULL) {
+ if (vm->frame->exception.catch != NULL) {
e = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_exception_t));
if (nxt_slow_path(e == NULL)) {
return NXT_ERROR;
}
- *e = vm->frame->u.exception;
- vm->frame->u.exception.next = e;
+ *e = vm->frame->exception;
+ vm->frame->exception.next = e;
}
- vm->frame->u.exception.catch = vm->current + (njs_ret_t) offset;
+ vm->frame->exception.catch = vm->current + (njs_ret_t) offset;
njs_set_invalid(value);
{
njs_exception_t *e;
- e = vm->frame->u.exception.next;
+ e = vm->frame->exception.next;
if (e == NULL) {
- vm->frame->u.exception.catch = NULL;
+ vm->frame->exception.catch = NULL;
} else {
- vm->frame->u.exception = *e;
+ vm->frame->exception = *e;
nxt_mem_cache_free(vm->mem_cache_pool, e);
}
return njs_vmcode_try_end(vm, exception, offset);
}
- vm->frame->u.exception.catch = vm->current + (njs_ret_t) offset;
+ vm->frame->exception.catch = vm->current + (njs_ret_t) offset;
return sizeof(njs_vmcode_catch_t);
}
}
-njs_ret_t
+static const njs_vmcode_1addr_t njs_trap_strings[] = {
+ { .code = { .operation = njs_vmcode_string_primitive,
+ .operands = NJS_VMCODE_1OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL },
+ .index = 0 },
+ { .code = { .operation = njs_vmcode_string_primitive,
+ .operands = NJS_VMCODE_1OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL },
+ .index = 1 },
+ { .code = { .operation = njs_vmcode_restart,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vmcode_1addr_t njs_trap_numbers[] = {
+ { .code = { .operation = njs_vmcode_number_primitive,
+ .operands = NJS_VMCODE_1OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL },
+ .index = 0 },
+ { .code = { .operation = njs_vmcode_number_primitive,
+ .operands = NJS_VMCODE_1OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL },
+ .index = 1 },
+ { .code = { .operation = njs_vmcode_restart,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vmcode_1addr_t njs_trap_number[] = {
+ { .code = { .operation = njs_vmcode_number_primitive,
+ .operands = NJS_VMCODE_1OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL },
+ .index = 0 },
+ { .code = { .operation = njs_vmcode_restart,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vm_trap_t njs_vm_traps[] = {
+ /* NJS_TRAP_PROPERTY */ { &njs_trap_strings[1], 0 },
+ /* NJS_TRAP_STRINGS */ { &njs_trap_strings[0], 0 },
+ /* NJS_TRAP_INCDEC */ { &njs_trap_numbers[1], 1 },
+ /* NJS_TRAP_NUMBERS */ { &njs_trap_numbers[0], 0 },
+ /* NJS_TRAP_NUMBER */ { &njs_trap_number[0], 0 },
+};
+
+
+static njs_ret_t
+njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
+ njs_value_t *value2)
+{
+ size_t size;
+ njs_value_t *values;
+ njs_native_frame_t *frame;
+
+ size = NJS_NATIVE_FRAME_SIZE + 3 * sizeof(njs_value_t);
+
+ frame = njs_function_frame_alloc(vm, size);
+ if (nxt_slow_path(frame == NULL)) {
+ return NXT_ERROR;
+ }
+
+ frame->ctor = 0;
+
+ values = njs_native_data(frame);
+ njs_set_invalid(&values[0]);
+ values[2] = *value2;
+
+ frame->trap_reference = njs_vm_traps[trap].reference_value;
+
+ if (njs_vm_traps[trap].reference_value) {
+ values[1].data.u.value = value1;
+
+ } else {
+ values[1] = *value1;
+ }
+
+ frame->u.restart = vm->current;
+ vm->current = (u_char *) njs_vm_traps[trap].code;
+
+ return NXT_OK;
+}
+
+
+static njs_ret_t
njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
{
u_char *restart;
*retval = vm->retval;
- if (frame->start) {
+ if (frame->first) {
nxt_mem_cache_free(vm->mem_cache_pool, frame);
}
typedef struct njs_object_init_s njs_object_init_t;
typedef struct njs_object_value_s njs_object_value_t;
typedef struct njs_array_s njs_array_t;
-typedef struct njs_function_script_s njs_function_script_t;
+typedef struct njs_function_lambda_s njs_function_lambda_t;
typedef struct njs_regexp_s njs_regexp_t;
typedef struct njs_regexp_pattern_s njs_regexp_pattern_t;
typedef struct njs_extern_s njs_extern_t;
#endif
union {
- njs_function_script_t *script;
+ njs_function_lambda_t *lambda;
njs_native_t native;
- } code;
+ } u;
njs_value_t *args;
} njs_function_t;
* the maximum size of short string to 13.
*/
struct {
- njs_value_type_t type:8; /* 4 bits */
+ njs_value_type_t type:8; /* 4 bits */
/*
* The truth field is set during value assignment and then can be
* quickly tested by logical and conditional operations regardless
* and short_string.length so when string size and length are zero
* the string's value is false.
*/
- uint8_t truth;
+ uint8_t truth;
/* 0xff if u.data.string is external string. */
- uint8_t external0;
- uint8_t _spare;
+ uint8_t external0;
+ uint8_t _spare;
- /* A long string size. */
- uint32_t string_size;
+ /*
+ * A long string size.
+ * Besides this field is used in native reentrant methods to
+ * store size of local state data allocated on stack frame.
+ */
+ uint32_t string_size;
union {
- double number;
- njs_string_t *string;
- njs_object_t *object;
- njs_array_t *array;
- njs_object_value_t *object_value;
- njs_function_t *function;
- njs_regexp_t *regexp;
- njs_getter_t getter;
- njs_native_t method;
- njs_extern_t *external;
- njs_value_t *value;
- void *data;
+ double number;
+ njs_string_t *string;
+ njs_object_t *object;
+ njs_array_t *array;
+ njs_object_value_t *object_value;
+ njs_function_t *function;
+ njs_function_lambda_t *lambda;
+ njs_regexp_t *regexp;
+ njs_getter_t getter;
+ njs_native_t method;
+ njs_extern_t *external;
+ njs_value_t *value;
+ void *data;
} u;
} data;
struct {
- njs_value_type_t type:8; /* 4 bits */
+ njs_value_type_t type:8; /* 4 bits */
-#define NJS_STRING_SHORT 14
-#define NJS_STRING_LONG 15
+#define NJS_STRING_SHORT 14
+#define NJS_STRING_LONG 15
- uint8_t size:4;
- uint8_t length:4;
+ uint8_t size:4;
+ uint8_t length:4;
- u_char start[NJS_STRING_SHORT];
+ u_char start[NJS_STRING_SHORT];
} short_string;
- njs_value_type_t type:8; /* 4 bits */
+ njs_value_type_t type:8; /* 4 bits */
};
.u.function = & (njs_function_t) { \
.native = 1, \
.args_offset = 1, \
- .code.native = _function, \
+ .u.native = _function, \
} \
} \
}
} }
-#define njs_method(_method, _size) \
- { .data = { .type = NJS_NATIVE, \
- .truth = 1, \
- .string_size = _size, \
- .u = { .method = _method } \
- } }
-
-
typedef njs_ret_t (*njs_vmcode_operation_t)(njs_vm_t *vm, njs_value_t *value1,
njs_value_t *value2);
} njs_vmcode_3addr_t;
-typedef struct {
- njs_vmcode_t code;
- njs_index_t retval;
-} njs_vmcode_stop_t;
-
-
typedef struct {
njs_vmcode_t code;
njs_index_t index;
typedef struct {
njs_vmcode_t code;
njs_index_t retval;
- njs_function_script_t *function;
-} njs_vmcode_function_create_t;
+ njs_function_lambda_t *lambda;
+} njs_vmcode_function_t;
typedef struct {
typedef struct {
njs_vmcode_t code;
- njs_index_t function;
njs_index_t name;
-} njs_vmcode_function_t;
+} njs_vmcode_function_frame_t;
typedef struct {
njs_vmcode_t code;
- njs_index_t function;
njs_index_t object;
njs_index_t method;
-} njs_vmcode_method_t;
+} njs_vmcode_method_frame_t;
typedef struct {
njs_vmcode_t code;
njs_index_t retval;
- njs_index_t function;
-} njs_vmcode_call_t;
+} njs_vmcode_function_call_t;
+
+
+typedef struct {
+ njs_vmcode_t code;
+ njs_index_t retval;
+} njs_vmcode_return_t;
+
+
+typedef struct {
+ njs_vmcode_t code;
+ njs_index_t retval;
+} njs_vmcode_stop_t;
typedef struct {
void njs_value_retain(njs_value_t *value);
void njs_value_release(njs_vm_t *vm, njs_value_t *value);
-njs_ret_t njs_vmcode_object_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_object(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_array_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_array(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_function_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *invld2);
-njs_ret_t njs_vmcode_regexp_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *invld2);
njs_ret_t njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
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_function(njs_vm_t *vm, njs_value_t *name,
- njs_value_t *invld);
-njs_ret_t njs_vmcode_method(njs_vm_t *vm, njs_value_t *object,
+njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *invld,
+ njs_value_t *name);
+njs_ret_t njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object,
njs_value_t *method);
-njs_ret_t njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval);
+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_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
njs_value_t *retval);
-njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *narg);
-njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *narg);
-njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
- njs_value_t *invld2);
-
-nxt_noinline void njs_number_set(njs_value_t *value, double num);
+void njs_number_set(njs_value_t *value, double num);
nxt_int_t njs_builtin_objects_create(njs_vm_t *vm);
nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm);
*start = parser->lexer->start;
- ret = njs_generate_scope(vm, parser, node, njs_vmcode_stop);
+ ret = njs_generate_scope(vm, parser, node);
if (nxt_slow_path(ret != NXT_OK)) {
return NJS_ERROR;
}
frame->native.previous = NULL;
frame->native.arguments = NULL;
- frame->native.start = 1;
+ frame->native.first = 1;
- frame->native.u.exception.next = NULL;
- frame->native.u.exception.catch = NULL;
+ frame->native.exception.next = NULL;
+ frame->native.exception.catch = NULL;
frame->prev_arguments = NULL;
frame->local = NULL;
frame->closure = NULL;
- frame->native.size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size);
+ frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size);
values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE;
- frame->native.last = values + scope_size;
+ frame->native.free = values + scope_size;
nvm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values;
memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope,
}
-void
-njs_vm_return(njs_vm_t *vm, njs_value_t *retval)
+njs_ret_t
+njs_vm_return_string(njs_vm_t *vm, u_char *start, size_t size)
{
- vm->retval = *retval;
+ return njs_string_create(vm, &vm->retval, start, size, 0);
}
void **external);
NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm);
-NXT_EXPORT void njs_vm_return(njs_vm_t *vm, njs_value_t *retval);
+NXT_EXPORT njs_ret_t njs_vm_return_string(njs_vm_t *vm, u_char *start,
+ size_t size);
NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval);
NXT_EXPORT nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval);
{ nxt_string("typeof /./i"),
nxt_string("object") },
- { nxt_string("typeof $r"),
- nxt_string("undefined") },
-
{ nxt_string("typeof a"),
nxt_string("undefined") },
{ nxt_string("a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(1, 3)"),
nxt_string("§±") },
- { nxt_string("a = $r.uri; s = a.fromUTF8(); s.length +' '+ s"),
- nxt_string("3 АБВ") },
-
- { nxt_string("a = $r.uri; s = a.fromUTF8(2); s.length +' '+ s"),
- nxt_string("2 БВ") },
-
- { nxt_string("a = $r.uri; s = a.fromUTF8(2, 4); s.length +' '+ s"),
- nxt_string("1 Б") },
-
- { nxt_string("a = $r.uri; a +' '+ a.length +' '+ a"),
- nxt_string("АБВ 6 АБВ") },
-
- { nxt_string("$r.uri = 'αβγ'; a = $r.uri; a.length +' '+ a"),
- nxt_string("6 αβγ") },
-
- { nxt_string("$r.uri.length +' '+ $r.uri"),
- nxt_string("6 АБВ") },
-
- { nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
- nxt_string("4 БВ") },
-
- { nxt_string("a = $r.host; a +' '+ a.length +' '+ a"),
- nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
-
- { nxt_string("a = $r.host; a.substr(2, 2)"),
- nxt_string("Б") },
-
- { nxt_string("a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
- nxt_string("User-Agent|АБВ 17 User-Agent|АБВ") },
-
- { nxt_string("var a='';"
- "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
- "a"),
- nxt_string("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
-
- { nxt_string("$r.nonexistent"),
- nxt_string("undefined") },
-
{ nxt_string("a = 'abcdefgh'; a.substr(3, 15)"),
nxt_string("defgh") },
" valueOf: function() { return 0 } }; '12'[n]"),
nxt_string("2") },
- /**/
+ /* Externals. */
+
+ { nxt_string("typeof $r"),
+ nxt_string("undefined") },
+
+ { nxt_string("a = $r.uri; s = a.fromUTF8(); s.length +' '+ s"),
+ nxt_string("3 АБВ") },
+
+ { nxt_string("a = $r.uri; s = a.fromUTF8(2); s.length +' '+ s"),
+ nxt_string("2 БВ") },
+
+ { nxt_string("a = $r.uri; s = a.fromUTF8(2, 4); s.length +' '+ s"),
+ nxt_string("1 Б") },
+
+ { nxt_string("a = $r.uri; a +' '+ a.length +' '+ a"),
+ nxt_string("АБВ 6 АБВ") },
+
+ { nxt_string("$r.uri = 'αβγ'; a = $r.uri; a.length +' '+ a"),
+ nxt_string("6 αβγ") },
+
+ { nxt_string("$r.uri.length +' '+ $r.uri"),
+ nxt_string("6 АБВ") },
+
+ { nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
+ nxt_string("4 БВ") },
+
+ { nxt_string("a = $r.host; a +' '+ a.length +' '+ a"),
+ nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
+
+ { nxt_string("a = $r.host; a.substr(2, 2)"),
+ nxt_string("Б") },
+
+ { nxt_string("a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
+ nxt_string("User-Agent|АБВ 17 User-Agent|АБВ") },
+
+ { nxt_string("var a='';"
+ "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
+ "a"),
+ nxt_string("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
+
+ { nxt_string("$r.external('YES')"),
+ nxt_string("АБВ") },
+
+#if 0
+ { nxt_string("$r.external.call($r, 'YES')"),
+ nxt_string("АБВ") },
+
+ { nxt_string("$r.external.apply($r, ['YES'])"),
+ nxt_string("АБВ") },
+#endif
+
+ { nxt_string("$r.nonexistent"),
+ nxt_string("undefined") },
{ nxt_string("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.charCodeAt(5)"),
nxt_string("1077") },
{ nxt_string("'abc ABC aBc'.match(/abc/ig) +''"),
nxt_string("abc,ABC,aBc") },
+ /* Functions. */
+
+ { nxt_string("var a = 1; a()"),
+ nxt_string("TypeError") },
+
+ { nxt_string("var o = {a:1}; o.a()"),
+ nxt_string("TypeError") },
+
{ nxt_string("var q = 1; function x(a, b, c) { q = a } x(5); q"),
nxt_string("5") },
{ nxt_string("function f(a) { return (a > 1) ? a * f(a - 1) : 1 } f(10)"),
nxt_string("3628800") },
+ { nxt_string("var g = function f(a) { return (a > 1) ? a * f(a - 1) : 1 };"
+ "g(10)"),
+ nxt_string("3628800") },
+
+ { nxt_string("(function f(a) { return (a > 1) ? a * f(a - 1) : 1 })(10)"),
+ nxt_string("3628800") },
+
/* Recursive fibonacci. */
{ nxt_string("function fibo(n) {"
{ nxt_string("function f() { return 5 } f()"),
nxt_string("5") },
+ { nxt_string("function g(x) { return x + 1 }"
+ "function f(x) { return x } f(g)(2)"),
+ nxt_string("3") },
+
{ nxt_string("function f() { return 5 } f(1)"),
nxt_string("5") },
{ nxt_string("a = {}; function f(a) { return a + 1 } a.b = f(2); a.b"),
nxt_string("3") },
+ { nxt_string("(function(x) { return x + 1 })(2)"),
+ nxt_string("3") },
+
+ { nxt_string("(function(x) { return x + 1 }(2))"),
+ nxt_string("3") },
+
{ nxt_string("a = (function() { return 1 })(); a"),
nxt_string("1") },
{ nxt_string("a = 0, function(a) { return a + 1 }(2); a"),
nxt_string("0") },
+ { nxt_string("a = (0, function(a) { return a + 1 }(2)); a"),
+ nxt_string("3") },
+
+ { nxt_string("var a = +function f(a) { return a + 1 }(2)"
+ "var b = f(5); a"),
+ nxt_string("ReferenceError") },
+
{ nxt_string("var o = { f: function(a) { return a * 2 } }; o.f(5)"),
nxt_string("10") },
}
+static njs_ret_t
+njs_unit_test_method_external(njs_vm_t *vm, njs_param_t *param)
+{
+ nxt_int_t ret;
+ nxt_str_t s;
+ uintptr_t next;
+ njs_unit_test_req *r;
+
+ next = 0;
+
+ if (param->nargs != 0) {
+
+ ret = njs_value_string_copy(vm, &s, njs_argument(param->args, 0),
+ &next);
+
+ if (ret == NXT_OK && s.len == 3 && memcmp(s.data, "YES", 3) == 0) {
+ r = njs_value_data(param->object);
+ njs_vm_return_string(vm, r->uri.data, r->uri.len);
+
+ return NXT_OK;
+ }
+ }
+
+ return NXT_ERROR;
+}
+
+
static njs_ret_t
njs_unit_test_undefined_external(njs_vm_t *vm, njs_value_t *value, void *obj,
uintptr_t data)
NULL,
0 },
+ { nxt_string("external"),
+ NJS_EXTERN_METHOD,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ njs_unit_test_method_external,
+ 0 },
+
};