From: Igor Sysoev Date: Thu, 11 Feb 2016 15:42:21 +0000 (+0300) Subject: Function.apply() works with continuation. X-Git-Tag: 0.1.0~63 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=2204723075675a8e03281f29753a48f6bec2789d;p=njs.git Function.apply() works with continuation. --- diff --git a/njs/njs_function.c b/njs/njs_function.c index 71defc10..9bf68249 100644 --- a/njs/njs_function.c +++ b/njs/njs_function.c @@ -19,6 +19,19 @@ #include +typedef struct { + njs_continuation_t continuation; + njs_function_t *function; +} njs_function_apply_t; + + +static nxt_int_t njs_function_apply_frame(njs_vm_t *vm, + njs_function_t *function, njs_value_t *this, njs_value_t *args, + nxt_uint_t nargs); +static njs_ret_t njs_function_prototype_apply_continuation(njs_vm_t *vm, + njs_param_t *param); + + njs_function_t * njs_function_alloc(njs_vm_t *vm) { @@ -326,6 +339,7 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param) njs_array_t *array; njs_value_t *args; njs_function_t *function; + njs_function_apply_t *apply; njs_vmcode_function_call_t *code; if (!njs_is_function(param->this)) { @@ -363,7 +377,33 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param) } } - return function->u.native(vm, &p); + ret = njs_function_apply_frame(vm, function, p.this, p.args, p.nargs); + + if (nxt_fast_path(ret == NXT_OK)) { + apply = nxt_mem_cache_alloc(vm->mem_cache_pool, + sizeof(njs_function_apply_t)); + if (nxt_slow_path(apply == NULL)) { + return NXT_ERROR; + } + + p.this = vm->frame->arguments - 1; + p.args = vm->frame->arguments; + + /* Skip the "apply" method frame. */ + vm->frame->previous->skip = 1; + + apply->continuation.function = + njs_function_prototype_apply_continuation; + apply->continuation.this = p.this; + apply->continuation.args = p.args; + apply->continuation.nargs = p.nargs; + apply->function = function; + vm->frame->continuation = &apply->continuation; + + return njs_function_prototype_apply_continuation(vm, &p); + } + + return ret; } if (nargs < 2) { @@ -397,6 +437,57 @@ type_error: } +static nxt_int_t +njs_function_apply_frame(njs_vm_t *vm, njs_function_t *function, + njs_value_t *this, njs_value_t *args, nxt_uint_t nargs) +{ + size_t size; + njs_value_t *p; + njs_native_frame_t *frame; + + size = NJS_NATIVE_FRAME_SIZE + function->local_state_size + + (nargs + 1) * sizeof(njs_value_t); + + frame = njs_function_frame_alloc(vm, size); + if (nxt_slow_path(frame == NULL)) { + return NXT_ERROR; + } + + frame->function = function; + + p = (njs_value_t *) ((u_char *) njs_native_data(frame) + + function->local_state_size); + frame->arguments = p + 1; + vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = frame->arguments; + + frame->previous = vm->frame; + vm->frame = frame; + + *p = *this; + memcpy(p + 1, args, nargs * sizeof(njs_value_t)); + + return NXT_OK; +} + + +static njs_ret_t +njs_function_prototype_apply_continuation(njs_vm_t *vm, njs_param_t *param) +{ + njs_ret_t ret; + njs_function_apply_t *apply; + + apply = (njs_function_apply_t *) vm->frame->continuation; + + ret = njs_normalize_args(vm, param->this, apply->function->args_types, + param->nargs + 1); + if (ret != NJS_OK) { + return ret; + } + + return apply->function->u.native(vm, param); +} + + static njs_ret_t njs_function_prototype_bind(njs_vm_t *vm, njs_param_t *param) { diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 6ec61334..18007a62 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -2305,10 +2305,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("''.concat.call(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)"), nxt_string("0123456789") }, -#if 0 { nxt_string("''.concat.apply(0, [1, 2, 3, 4, 5, 6, 7, 8, 9])"), nxt_string("0123456789") }, -#endif { nxt_string("var s = { toString: function() { return '123' } };" "var a = 'abc'; a.concat('абв', s)"),