typedef struct {
- njs_continuation_t cont;
- njs_value_t *values;
- uint32_t max;
+ njs_continuation_t cont;
+ njs_value_t *values;
+ uint32_t max;
} njs_array_join_t;
typedef struct {
- njs_value_t retval;
- int32_t index;
- uint32_t length;
+ union {
+ njs_continuation_t cont;
+ u_char padding[NJS_CONTINUATION_SIZE];
+ };
+ njs_value_t retval;
+ int32_t index;
+ uint32_t length;
} njs_array_next_t;
+static njs_ret_t
+njs_array_prototype_to_string_continuation(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t retval);
static njs_ret_t njs_array_prototype_join_continuation(njs_vm_t *vm,
njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
static nxt_noinline njs_value_t *njs_array_copy(njs_value_t *dst,
njs_value_t *src);
-static nxt_noinline nxt_int_t njs_array_next(njs_value_t *value, nxt_uint_t n,
- nxt_uint_t length);
+static nxt_noinline njs_ret_t njs_array_prototype_for_each_cont(njs_vm_t *vm,
+ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static nxt_noinline njs_ret_t njs_array_prototype_some_cont(njs_vm_t *vm,
+ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static nxt_noinline njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm,
+ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm,
+ njs_value_t * args, nxt_uint_t nargs);
+static nxt_noinline nxt_int_t njs_array_iterator_next(njs_value_t *value,
+ nxt_uint_t n, nxt_uint_t length);
+static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm,
+ njs_array_next_t *next, njs_value_t *args, nxt_uint_t nargs);
njs_value_t *
/*
* ECMAScript 5.1: try first to use object method "join", then
* use the standard built-in method Object.prototype.toString().
+ * Array.toString() must be a continuation otherwise it may
+ * endlessly call Array.join().
*/
static njs_ret_t
njs_index_t retval)
{
njs_object_prop_t *prop;
+ njs_continuation_t *cont;
nxt_lvlhsh_query_t lhq;
+ cont = (njs_continuation_t *) njs_continuation(vm->frame);
+ cont->function = njs_array_prototype_to_string_continuation;
+
if (njs_is_object(&args[0])) {
lhq.key_hash = NJS_JOIN_HASH;
lhq.key.len = sizeof("join") - 1;
}
+static njs_ret_t
+njs_array_prototype_to_string_continuation(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t retval)
+{
+ /* Skip retval update. */
+ vm->frame->skip = 1;
+
+ return NXT_OK;
+}
+
+
static njs_ret_t
njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
goto empty;
}
+ join = (njs_array_join_t *) njs_continuation(vm->frame);
+ join->values = NULL;
+ join->max = 0;
max = 0;
for (i = 0; i < array->length; i++) {
}
if (max != 0) {
- join = nxt_mem_cache_alloc(vm->mem_cache_pool,
- sizeof(njs_array_join_t));
- if (nxt_slow_path(join == NULL)) {
- return NXT_ERROR;
- }
-
values = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
sizeof(njs_value_t) * max);
if (nxt_slow_path(values == NULL)) {
return NXT_ERROR;
}
+ join = (njs_array_join_t *) njs_continuation(vm->frame);
join->cont.function = njs_array_prototype_join_continuation;
- join->cont.args = args;
- join->cont.nargs = nargs;
join->values = values;
join->max = max;
- vm->frame->continuation = &join->cont;
n = 0;
njs_array_join_t *join;
njs_string_prop_t separator, string;
- join = (njs_array_join_t *) vm->frame->continuation;
-
- if (join != NULL) {
- values = join->values;
- max = join->max;
-
- } else {
- values = NULL;
- max = 0;
- }
+ join = (njs_array_join_t *) njs_continuation(vm->frame);
+ values = join->values;
+ max = join->max;
size = 0;
length = 0;
nxt_mem_cache_free(vm->mem_cache_pool, values);
- vm->frame->continuation = NULL;
-
return NXT_OK;
}
}
-nxt_inline nxt_int_t
-njs_array_iterator_args(njs_vm_t *vm, njs_value_t * args, nxt_uint_t nargs)
+static njs_ret_t
+njs_array_prototype_for_each(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
{
- if (nargs > 1 && njs_is_array(&args[0]) && njs_is_function(&args[1])) {
- return NXT_OK;
+ nxt_int_t ret;
+ njs_array_next_t *next;
+
+ ret = njs_array_iterator_args(vm, args, nargs);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
}
- vm->exception = &njs_exception_type_error;
+ next = njs_continuation(vm->frame);
+ next->cont.function = njs_array_prototype_for_each_cont;
- return NXT_ERROR;
+ return njs_array_prototype_for_each_cont(vm, args, nargs, unused);
}
static njs_ret_t
-njs_array_prototype_for_each(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
- njs_index_t unused)
+njs_array_prototype_for_each_cont(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
{
- nxt_int_t n, ret;
- njs_array_t *array;
njs_array_next_t *next;
- njs_value_t arguments[4];
- if (!vm->frame->reentrant) {
- vm->frame->reentrant = 1;
+ next = njs_continuation(vm->frame);
- ret = njs_array_iterator_args(vm, args, nargs);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
+ if (next->index < 0) {
+ vm->retval = njs_value_void;
+ return NXT_OK;
+ }
- array = args[0].data.u.array;
- n = njs_array_next(array->start, 0, array->length);
+ return njs_array_iterator_apply(vm, next, args, nargs);
+}
- if (n < 0) {
- vm->retval = njs_value_void;
- return NXT_OK;
- }
- next = njs_native_data(vm->frame);
- next->index = n;
- next->length = array->length;
+static njs_ret_t
+njs_array_prototype_some(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_int_t ret;
+ njs_array_next_t *next;
+
+ ret = njs_array_iterator_args(vm, args, nargs);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
}
- next = njs_native_data(vm->frame);
- n = next->index;
+ next = njs_continuation(vm->frame);
+ next->cont.function = njs_array_prototype_some_cont;
+ next->retval.data.truth = 0;
+
+ return njs_array_prototype_some_cont(vm, args, nargs, unused);
+}
- arguments[0] = (nargs > 2) ? args[2] : njs_value_void;
- /* GC: array elt, array */
- array = args[0].data.u.array;
- arguments[1] = array->start[n];
- njs_number_set(&arguments[2], n);
- arguments[3] = args[0];
- n = njs_array_next(array->start, ++n, next->length);
- next->index = n;
+static njs_ret_t
+njs_array_prototype_some_cont(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ njs_array_next_t *next;
+ const njs_value_t *retval;
- if (n < 0) {
- vm->current += sizeof(njs_vmcode_function_call_t);
+ next = njs_continuation(vm->frame);
+
+ if (njs_is_true(&next->retval)) {
+ retval = &njs_value_true;
+
+ } else if (next->index < 0) {
+ retval = &njs_value_false;
+
+ } else {
+ return njs_array_iterator_apply(vm, next, args, nargs);
}
- return njs_function_apply(vm, args[1].data.u.function, arguments, 4,
- (njs_index_t) &next->retval);
+ vm->retval = *retval;
+
+ return NXT_OK;
}
static njs_ret_t
-njs_array_prototype_some(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+njs_array_prototype_every(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
- nxt_int_t n, ret;
- njs_array_t *array;
+ nxt_int_t ret;
njs_array_next_t *next;
- njs_value_t arguments[4];
- if (!vm->frame->reentrant) {
- vm->frame->reentrant = 1;
+ ret = njs_array_iterator_args(vm, args, nargs);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
- ret = njs_array_iterator_args(vm, args, nargs);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
+ next = njs_continuation(vm->frame);
+ next->cont.function = njs_array_prototype_every_cont;
+ next->retval.data.truth = 1;
- array = args[0].data.u.array;
- n = njs_array_next(array->start, 0, array->length);
- next = njs_native_data(vm->frame);
- next->index = n;
- next->length = array->length;
+ return njs_array_prototype_every_cont(vm, args, nargs, unused);
+}
- } else {
- next = njs_native_data(vm->frame);
- if (njs_is_true(&next->retval)) {
- vm->retval = njs_value_true;
- return NXT_OK;
- }
- }
+static njs_ret_t
+njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ njs_array_next_t *next;
+ const njs_value_t *retval;
- n = next->index;
+ next = njs_continuation(vm->frame);
- if (n < 0) {
- vm->retval = njs_value_false;
- return NXT_OK;
- }
+ if (!njs_is_true(&next->retval)) {
+ retval = &njs_value_false;
- arguments[0] = (nargs > 2) ? args[2] : njs_value_void;
- /* GC: array elt, array */
- array = args[0].data.u.array;
- arguments[1] = array->start[n];
- njs_number_set(&arguments[2], n);
- arguments[3] = args[0];
+ } else if (next->index < 0) {
+ retval = &njs_value_true;
- next->index = njs_array_next(array->start, ++n, next->length);
+ } else {
+ return njs_array_iterator_apply(vm, next, args, nargs);
+ }
- return njs_function_apply(vm, args[1].data.u.function, arguments, 4,
- (njs_index_t) &next->retval);
+ vm->retval = *retval;
+
+ return NXT_OK;
}
-static njs_ret_t
-njs_array_prototype_every(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
- njs_index_t unused)
+static nxt_noinline njs_ret_t
+njs_array_iterator_args(njs_vm_t *vm, njs_value_t * args, nxt_uint_t nargs)
{
- nxt_int_t n, ret;
njs_array_t *array;
njs_array_next_t *next;
- njs_value_t arguments[4];
- if (!vm->frame->reentrant) {
- vm->frame->reentrant = 1;
-
- ret = njs_array_iterator_args(vm, args, nargs);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
+ if (nargs > 1 && njs_is_array(&args[0]) && njs_is_function(&args[1])) {
array = args[0].data.u.array;
- n = njs_array_next(array->start, 0, array->length);
- next = njs_native_data(vm->frame);
- next->index = n;
+ next = njs_continuation(vm->frame);
next->length = array->length;
+ next->index = njs_array_iterator_next(array->start, 0, array->length);
- } else {
- next = njs_native_data(vm->frame);
-
- if (!njs_is_true(&next->retval)) {
- vm->retval = njs_value_false;
- return NXT_OK;
- }
- }
-
- n = next->index;
-
- if (n < 0) {
- vm->retval = njs_value_true;
return NXT_OK;
}
- arguments[0] = (nargs > 2) ? args[2] : njs_value_void;
- /* GC: array elt, array */
- array = args[0].data.u.array;
- arguments[1] = array->start[n];
- njs_number_set(&arguments[2], n);
- arguments[3] = args[0];
-
- next->index = njs_array_next(array->start, ++n, next->length);
+ vm->exception = &njs_exception_type_error;
- return njs_function_apply(vm, args[1].data.u.function, arguments, 4,
- (njs_index_t) &next->retval);
+ return NXT_ERROR;
}
static nxt_noinline nxt_int_t
-njs_array_next(njs_value_t *value, nxt_uint_t n, nxt_uint_t length)
+njs_array_iterator_next(njs_value_t *value, nxt_uint_t n, nxt_uint_t length)
{
while (n < length) {
if (njs_is_valid(&value[n])) {
}
+static nxt_noinline njs_ret_t
+njs_array_iterator_apply(njs_vm_t *vm, njs_array_next_t *next,
+ njs_value_t *args, nxt_uint_t nargs)
+{
+ nxt_int_t n;
+ njs_array_t *array;
+ njs_value_t arguments[4];
+
+ n = next->index;
+
+ arguments[0] = (nargs > 2) ? args[2] : njs_value_void;
+ /* GC: array elt, array */
+ array = args[0].data.u.array;
+ arguments[1] = array->start[n];
+ njs_number_set(&arguments[2], n);
+ arguments[3] = args[0];
+
+ next->index = njs_array_iterator_next(array->start, ++n, next->length);
+
+ return njs_function_apply(vm, args[1].data.u.function, arguments, 4,
+ (njs_index_t) &next->retval);
+}
+
+
static const njs_object_prop_t njs_array_prototype_properties[] =
{
{
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_array_prototype_to_string, 0, 0),
+ .value = njs_native_function(njs_array_prototype_to_string,
+ NJS_CONTINUATION_SIZE, 0),
},
{
#include <string.h>
-typedef struct {
- njs_continuation_t cont;
- njs_function_t *function;
-} njs_function_apply_t;
-
-
-static njs_ret_t njs_function_prototype_apply_continuation(njs_vm_t *vm,
- njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
-
-
njs_function_t *
njs_function_alloc(njs_vm_t *vm)
{
njs_ret_t
njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs,
- nxt_bool_t ctor)
+ size_t reserve, nxt_bool_t ctor)
{
size_t size;
nxt_uint_t n;
njs_value_t *value, *bound;
njs_native_frame_t *frame;
- size = NJS_NATIVE_FRAME_SIZE
- + function->continuation_size
- + (function->args_offset + nargs - 1) * sizeof(njs_value_t);
+ nargs--;
+
+ reserve = nxt_max(reserve, function->continuation_size);
+
+ size = NJS_NATIVE_FRAME_SIZE + reserve
+ + (function->args_offset + nargs) * sizeof(njs_value_t);
frame = njs_function_frame_alloc(vm, size);
if (nxt_slow_path(frame == NULL)) {
}
frame->function = function;
+ frame->nargs = function->args_offset + nargs;
frame->ctor = ctor;
- value = (njs_value_t *) ((u_char *) njs_native_data(frame)
- + function->continuation_size);
+ value = (njs_value_t *) ((u_char *) njs_continuation(frame) + reserve);
bound = function->bound;
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = value;
if (args != NULL) {
- memcpy(value, args, (nargs - 1) * sizeof(njs_value_t));
+ memcpy(value, args, nargs * sizeof(njs_value_t));
}
return NXT_OK;
njs_function_apply(njs_vm_t *vm, njs_function_t *function, njs_value_t *args,
nxt_uint_t nargs, njs_index_t retval)
{
- njs_ret_t ret;
+ size_t reserve;
+ njs_ret_t ret;
+ njs_continuation_t *cont;
if (function->native) {
- return function->u.native(vm, args, nargs, retval);
+
+ if (function->continuation_size == 0 && function->bound == NULL) {
+ return function->u.native(vm, args, nargs, retval);
+ }
+
+ reserve = nxt_align_size(sizeof(njs_continuation_t),
+ sizeof(njs_value_t)),
+
+ ret = njs_function_native_frame(vm, function, &args[0], &args[1],
+ nargs, reserve, 0);
+ if (ret != NJS_OK) {
+ return ret;
+ }
+
+ cont = njs_continuation(vm->frame);
+
+ cont->function = function->u.native;
+ cont->retval = retval;
+
+ cont->return_address = vm->current;
+ vm->current = (u_char *) njs_continuation_nexus;
+
+ return NJS_APPLIED;
}
ret = njs_function_frame(vm, function, &args[0], &args[1], nargs - 1, 0);
}
native_frame->function = function;
+ native_frame->nargs = function->args_offset + nargs - 1;
native_frame->ctor = ctor;
value = (njs_value_t *) ((u_char *) native_frame + NJS_FRAME_SIZE);
return NXT_ERROR;
}
- nargs = nargs - 1;
- function = args[0].data.u.function;
-
- if (function->native) {
-
- if (nargs == 0) {
- nargs++;
- args[1] = njs_value_void;
- }
-
- ret = njs_normalize_args(vm, &args[1], function->args_types, nargs);
+ this = &args[1];
+ nargs--;
- if (ret != NJS_OK) {
- return ret;
- }
+ if (nargs == 0) {
+ this = (njs_value_t *) &njs_value_void;
- if (function->continuation_size == 0) {
- args = &args[1];
+ } else {
+ nargs--;
+ }
- } else {
- ret = njs_function_native_frame(vm, function, &args[1], &args[2],
- nargs, 0);
- if (ret != NJS_OK) {
- return ret;
- }
+ function = args[0].data.u.function;
- /* Skip the "call" method frame. */
- vm->frame->previous->skip = 1;
+ if (function->native) {
- args = vm->frame->arguments - function->args_offset;
+ ret = njs_function_native_frame(vm, function, this, &args[2],
+ nargs + 1, 0, 0);
+ if (nxt_slow_path(ret != NJS_OK)) {
+ return ret;
}
- return function->u.native(vm, args, nargs, retval);
- }
-
- this = &args[1];
-
- if (nargs == 0) {
- this = (njs_value_t *) &njs_value_void;
+ /* Skip the "call" method frame. */
+ vm->frame->previous->skip = 1;
- } else {
- nargs--;
+ return NJS_APPLIED;
}
ret = njs_function_frame(vm, function, this, &args[2], nargs, 0);
njs_function_prototype_apply(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t retval)
{
- njs_ret_t ret;
- njs_array_t *array;
- njs_value_t *this;
- njs_function_t *function;
- njs_function_apply_t *apply;
+ njs_ret_t ret;
+ njs_array_t *array;
+ njs_value_t *this;
+ njs_function_t *function;
if (!njs_is_function(&args[0])) {
goto type_error;
}
if (function->native) {
- nargs++;
-
- ret = njs_function_native_frame(vm, function, this, args, nargs, 0);
+ ret = njs_function_native_frame(vm, function, this, args,
+ nargs + 1, 0, 0);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
-// apply = njs_continuation(vm->frame);
- apply = nxt_mem_cache_alloc(vm->mem_cache_pool,
- sizeof(njs_function_apply_t));
- if (nxt_slow_path(apply == NULL)) {
- return NXT_ERROR;
- }
-
- args = vm->frame->arguments - function->args_offset;
-
/* Skip the "apply" method frame. */
vm->frame->previous->skip = 1;
- apply->cont.function = njs_function_prototype_apply_continuation;
- apply->cont.args = args;
- apply->cont.nargs = nargs;
- apply->function = function;
- vm->frame->continuation = &apply->cont;
-
- return njs_function_prototype_apply_continuation(vm, args, nargs,
- retval);
+ return NJS_APPLIED;
}
ret = njs_function_frame(vm, function, this, args, nargs, 0);
- if (nxt_fast_path(ret == NXT_OK)) {
- /* Skip the "apply" method frame. */
- vm->frame->previous->skip = 1;
-
- return njs_function_call(vm, retval,
- sizeof(njs_vmcode_function_call_t));
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
}
- return ret;
+ /* Skip the "apply" method frame. */
+ vm->frame->previous->skip = 1;
+
+ return njs_function_call(vm, retval, sizeof(njs_vmcode_function_call_t));
type_error:
}
-static njs_ret_t
-njs_function_prototype_apply_continuation(njs_vm_t *vm, njs_value_t *args,
- nxt_uint_t nargs, njs_index_t retval)
-{
- njs_ret_t ret;
- njs_function_t *function;
- njs_function_apply_t *apply;
-
- apply = (njs_function_apply_t *) vm->frame->continuation;
- function = apply->function;
-
- ret = njs_normalize_args(vm, args, function->args_types, nargs);
-
- if (ret == NJS_OK) {
- return function->u.native(vm, args, nargs, retval);
- }
-
- return ret;
-}
-
-
static njs_ret_t
njs_function_prototype_bind(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
.type = NJS_METHOD,
.name = njs_string("apply"),
- .value = njs_native_function(njs_function_prototype_apply,
- njs_continuation_size(njs_function_apply_t), 0),
+ .value = njs_native_function(njs_function_prototype_apply, 0, 0),
},
{
#define NJS_FRAME_SIZE \
nxt_align_size(sizeof(njs_frame_t), sizeof(njs_value_t))
-/* The retval field are not used in the global frame. */
+/* The retval field is not used in the global frame. */
#define NJS_GLOBAL_FRAME_SIZE \
nxt_align_size(offsetof(njs_frame_t, retval), sizeof(njs_value_t))
#define NJS_FRAME_SPARE_SIZE 512
-#define njs_native_data(frame) \
- (void *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE)
-
#define njs_continuation(frame) \
(void *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE)
#define njs_continuation_size(size) \
nxt_align_size(sizeof(size), sizeof(njs_value_t))
-
-typedef struct {
- njs_function_native_t function;
- njs_value_t *args;
- nxt_uint_t nargs;
-} njs_continuation_t;
+#define NJS_CONTINUATION_SIZE njs_continuation_size(njs_continuation_t)
typedef struct njs_exception_s njs_exception_t;
u_char *free;
njs_function_t *function;
- njs_continuation_t *continuation;
njs_native_frame_t *previous;
njs_value_t *arguments;
uint32_t free_size;
+ uint16_t nargs;
+
/* Function is called as constructor with "new" keyword. */
uint8_t ctor; /* 1 bit */
/* Skip the Function.call() and Function.apply() methods frames. */
uint8_t skip:1; /* 1 bit */
- /* The function is reentrant. */
- uint8_t reentrant:1; /* 1 bit */
-
- /* A frame of trap generated from continuation. */
- uint8_t trap_frame:1; /* 1 bit */
-
/* A number of trap tries, it can be no more than three. */
uint8_t trap_tries:2; /* 2 bits */
njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
njs_ret_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs,
- nxt_bool_t ctor);
+ size_t reserve, nxt_bool_t ctor);
njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function,
njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, nxt_bool_t ctor);
njs_ret_t njs_function_call(njs_vm_t *vm, njs_index_t retval, size_t advance);
parser->code_size, code_size);
if (nxt_slow_path(parser->code_size < code_size)) {
+ vm->exception = &njs_exception_internal_error;
return NXT_ERROR;
}
njs_value_t *val2);
static nxt_noinline nxt_bool_t njs_values_strict_equal(njs_value_t *val1,
njs_value_t *val2);
+static njs_ret_t njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *invld2);
static njs_native_frame_t *
njs_function_previous_frame(njs_native_frame_t *frame);
static njs_ret_t njs_function_frame_free(njs_vm_t *vm,
function = value->data.u.function;
if (function->native) {
- ret = njs_function_native_frame(vm, function, &njs_value_void, NULL,
- func->code.nargs, func->code.ctor);
+ ret = njs_function_native_frame(vm, function, &njs_value_void,
+ NULL, func->code.nargs, 0,
+ func->code.ctor);
if (nxt_fast_path(ret == NXT_OK)) {
return sizeof(njs_vmcode_function_frame_t);
}
ret = njs_function_native_frame(vm, function, object, NULL,
- method->code.nargs,
+ method->code.nargs, 0,
method->code.ctor);
if (nxt_fast_path(ret == NXT_OK)) {
this.data.u.data = vm->external[ext->object];
ret = njs_function_native_frame(vm, ext->function, &this, NULL,
- method->code.nargs,
+ method->code.nargs, 0,
method->code.ctor);
if (nxt_fast_path(ret == NXT_OK)) {
njs_ret_t
njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
{
- njs_ret_t ret;
- nxt_uint_t nargs;
- njs_value_t *args;
- njs_function_t *function;
- njs_native_frame_t *frame;
- njs_continuation_t *continuation;
- njs_function_native_t native;
- njs_vmcode_function_call_t *call;
+ njs_ret_t ret;
+ nxt_uint_t nargs;
+ njs_value_t *args;
+ njs_function_t *function;
+ njs_continuation_t *cont;
+ njs_native_frame_t *frame;
function = vm->frame->function;
return 0;
}
- call = (njs_vmcode_function_call_t *) vm->current;
- args = vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] - function->args_offset;
+ args = vm->frame->arguments - function->args_offset;
+ nargs = vm->frame->nargs;
- continuation = vm->frame->continuation;
+ ret = njs_normalize_args(vm, args, function->args_types, nargs);
+ if (ret != NJS_OK) {
+ return ret;
+ }
- if (continuation == NULL) {
- nargs = function->args_offset + call->code.nargs - 1;
+ if (function->continuation_size != 0) {
+ cont = njs_continuation(vm->frame);
- ret = njs_normalize_args(vm, args, function->args_types, nargs);
- if (ret != NJS_OK) {
- return ret;
- }
+ cont->function = function->u.native;
+ cont->retval = (njs_index_t) retval;
- native = function->u.native;
+ cont->return_address = vm->current + sizeof(njs_vmcode_function_call_t);
+ vm->current = (u_char *) njs_continuation_nexus;
- } else {
- args = continuation->args;
- nargs = continuation->nargs;
- native = continuation->function;
+ return 0;
}
- ret = native(vm, args, nargs, (njs_index_t) retval);
+ ret = function->u.native(vm, args, nargs, (njs_index_t) retval);
/*
* A native method can return:
frame = vm->frame;
vm->frame = njs_function_previous_frame(frame);
-
(void) njs_function_frame_free(vm, frame);
/*
} else if (ret == NJS_APPLIED) {
/* A user-defined method has been prepared to run. */
ret = 0;
-
- } else if (ret == NXT_AGAIN) {
- /*
- * Revert nJSVM current address, execution will
- * continue on the same function after resumption.
- */
- vm->frame->reentrant = 1;
- vm->current -= sizeof(njs_vmcode_function_call_t);
}
return ret;
}
+const njs_vmcode_1addr_t njs_continuation_nexus[] = {
+ { .code = { .operation = njs_vmcode_continuation,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static njs_ret_t
+njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+{
+ njs_ret_t ret;
+ nxt_bool_t skip;
+ njs_value_t *args, *retval;
+ njs_native_frame_t *frame;
+ njs_continuation_t *cont;
+
+ frame = vm->frame;
+ cont = njs_continuation(frame);
+ args = frame->arguments - frame->function->args_offset;
+
+ ret = cont->function(vm, args, frame->nargs, cont->retval);
+
+ switch (ret) {
+
+ case NXT_OK:
+
+ frame = vm->frame;
+ skip = frame->skip;
+
+ vm->frame = njs_function_previous_frame(frame);
+ (void) njs_function_frame_free(vm, frame);
+
+ /*
+ * If a retval is in a callee arguments scope it
+ * must be in the previous callee arguments scope.
+ */
+ vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = vm->frame->arguments;
+
+ if (!skip) {
+ retval = njs_vmcode_operand(vm, cont->retval);
+ /*
+ * GC: value external/internal++ depending
+ * on vm->retval and retval type
+ */
+ *retval = vm->retval;
+ }
+
+ vm->current = cont->return_address;
+
+ return 0;
+
+ case NJS_APPLIED:
+ return 0;
+
+ default:
+ return ret;
+ }
+}
+
+
static njs_native_frame_t *
njs_function_previous_frame(njs_native_frame_t *frame)
{
value = frame->trap_scratch.data.u.value;
njs_set_invalid(&frame->trap_scratch);
- if (frame->continuation != NULL) {
- frame = njs_function_frame_alloc(vm, NJS_NATIVE_FRAME_SIZE);
-
- if (nxt_slow_path(frame == NULL)) {
- return NXT_ERROR;
- }
-
- frame->trap_frame = 1;
- }
-
frame->trap_values[1].data.u.value = value;
frame->trap_values[0] = *value;
njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *inlvd2)
{
- double num;
- njs_ret_t ret;
- njs_value_t *value;
- njs_native_frame_t *frame;
+ double num;
+ njs_ret_t ret;
+ njs_value_t *value;
value = &vm->frame->trap_values[0];
njs_number_set(value, num);
}
- frame = vm->frame;
- *frame->trap_values[1].data.u.value = *value;
+ *vm->frame->trap_values[1].data.u.value = *value;
vm->current = vm->frame->trap_restart;
- frame->trap_restart = NULL;
-
- if (frame->trap_frame) {
- vm->frame = frame->previous;
-
- if (frame->first) {
- nxt_mem_cache_free(vm->mem_cache_pool, frame);
- }
- }
+ vm->frame->trap_restart = NULL;
return 0;
}
njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *inlvd2)
{
- njs_ret_t ret;
- njs_value_t *value;
- njs_native_frame_t *frame;
+ njs_ret_t ret;
+ njs_value_t *value;
value = &vm->frame->trap_values[0];
ret = njs_primitive_value_to_string(vm, value, value);
if (nxt_fast_path(ret == NXT_OK)) {
- frame = vm->frame;
- *frame->trap_values[1].data.u.value = *value;
-
- vm->current = frame->trap_restart;
- frame->trap_restart = NULL;
-
- if (frame->trap_frame) {
- vm->frame = frame->previous;
+ *vm->frame->trap_values[1].data.u.value = *value;
- if (frame->first) {
- nxt_mem_cache_free(vm->mem_cache_pool, frame);
- }
- }
+ vm->current = vm->frame->trap_restart;
+ vm->frame->trap_restart = NULL;
}
}
njs_function_t *function;
njs_object_prop_t *prop;
nxt_lvlhsh_query_t lhq;
- njs_continuation_t *continuation;
static const uint32_t hashes[] = {
NJS_VALUE_OF_HASH,
nxt_string("toString"),
};
- continuation = vm->frame->continuation;
-
- if (continuation != NULL) {
- ret = continuation->function(vm, continuation->args,
- continuation->nargs,
- (njs_index_t) &vm->frame->trap_scratch);
- if (ret != NXT_OK) {
- return ret;
- }
-
- if (njs_is_primitive(&vm->retval)) {
- *value = vm->retval;
- njs_set_invalid(&vm->frame->trap_scratch);
- vm->frame->trap_tries = 0;
-
- return 1;
- }
- }
-
if (!njs_is_primitive(value)) {
retval = &vm->frame->trap_scratch;
if (ret == NJS_APPLIED) {
/*
- * A user-defined method has been prepared to
- * run. The method will return to the current
- * instruction and will restart it.
+ * A user-defined method or continuation have
+ * been prepared to run. The method will return
+ * to the current instruction and will restart it.
*/
ret = 0;
}
*retval = vm->retval;
- if (frame->trap_frame) {
- vm->frame = frame->previous;
-
- if (frame->first) {
- nxt_mem_cache_free(vm->mem_cache_pool, frame);
- }
- }
-
return ret;
}
}
-nxt_uint_t
-njs_vm_is_reentrant(njs_vm_t *vm)
-{
- return vm->frame->reentrant;
-}
-
-
nxt_int_t
njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value,
uintptr_t *next)
} njs_function_t;
+typedef struct njs_continuation_s njs_continuation_t;
+
+struct njs_continuation_s {
+ njs_function_native_t function;
+ u_char *return_address;
+ njs_index_t retval;
+};
+
+
union njs_value_s {
/*
* The njs_value_t size is 16 bytes and must be aligned to 16 bytes
typedef struct {
njs_vmcode_operation_t operation;
uint8_t operands; /* 2 bits */
- uint8_t retval; /* 1 bit */
- uint8_t ctor; /* 1 bit */
+ uint8_t retval; /* 1 bit */
+ uint8_t ctor; /* 1 bit */
#if (NXT_64BIT)
uint32_t nargs;
#else
extern const nxt_mem_proto_t njs_array_mem_proto;
extern const nxt_lvlhsh_proto_t njs_object_hash_proto;
+extern const njs_vmcode_1addr_t njs_continuation_nexus[];
+
#endif /* _NJS_VM_H_INCLUDED_ */
NXT_EXPORT njs_ret_t njs_void_set(njs_value_t *value);
NXT_EXPORT void *njs_value_data(njs_value_t *value);
-NXT_EXPORT nxt_uint_t njs_vm_is_reentrant(njs_vm_t *vm);
NXT_EXPORT nxt_int_t njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval,
njs_value_t *value, uintptr_t *next);
"f(2)"),
nxt_string("012") },
-#if 0
{ nxt_string("var f = String.prototype.concat.bind(0, 1);"
"var o = { toString: f }; o"),
nxt_string("01") },
-#endif
-#if 0
- { nxt_string("''.concat.bind(1,2,3,4).call(5,6,7,8)"),
+ { nxt_string("''.concat.bind(0, 1, 2, 3, 4).call(5, 6, 7, 8, 9)"),
nxt_string("012346789") },
-#endif
-#if 0
- { nxt_string("''.concat.bind(1,2,3,4).apply(5,[6,7,8])"),
+ { nxt_string("''.concat.bind(0, 1, 2, 3, 4).apply(5,[6, 7, 8, 9])"),
nxt_string("012346789") },
-#endif
+
+ { nxt_string("var f = Array.prototype.join.bind([0, 1, 2]); f()"),
+ nxt_string("0,1,2") },
+
+ { nxt_string("var f = Array.prototype.join.bind([0, 1, 2]);"
+ "var o = { toString: f }; o"),
+ nxt_string("0,1,2") },
+
+ { nxt_string("var f = Array.prototype.join.bind([0, 1, 2]); f('.')"),
+ nxt_string("0.1.2") },
+
+ { nxt_string("var f = Array.prototype.join.bind([0, 1, 2], '.');"
+ "var o = { toString: f }; o"),
+ nxt_string("0.1.2") },
+
+ { nxt_string("var f = Array.prototype.toString.bind([0, 1, 2]); f()"),
+ nxt_string("0,1,2") },
+
+ { nxt_string("var f = Array.prototype.toString.bind([0, 1, 2]);"
+ "var o = { toString: f }; o"),
+ nxt_string("0,1,2") },
{ nxt_string("var s = { toString: function() { return '123' } };"
"var a = 'abc'; a.concat('абв', s)"),