[njs] A user defined object method called as constructor did not
Igor Sysoev
igor at sysoev.ru
Wed Dec 7 20:44:21 UTC 2016
details: http://hg.nginx.org/njs/rev/2380d725ec7b
branches:
changeset: 276:2380d725ec7b
user: Igor Sysoev <igor at sysoev.ru>
date: Wed Dec 07 19:34:48 2016 +0300
description:
A user defined object method called as constructor did not
create correct prototype links in created objects.
Thanks to ??? (Hong Zhi Dao).
diffstat:
njs/njs_function.c | 7 +-
njs/njs_function.h | 3 +-
njs/njs_vm.c | 177 ++++++++++++++++++----------------------------
njs/test/njs_unit_test.c | 4 +
4 files changed, 82 insertions(+), 109 deletions(-)
diffs (298 lines):
diff -r 56d6fc12dc31 -r 2380d725ec7b njs/njs_function.c
--- a/njs/njs_function.c Wed Dec 07 15:02:00 2016 +0300
+++ b/njs/njs_function.c Wed Dec 07 19:34:48 2016 +0300
@@ -111,12 +111,14 @@ njs_function_native_frame(njs_vm_t *vm,
bound = function->bound;
if (bound == NULL) {
+ /* GC: njs_retain(this); */
*value++ = *this;
} else {
n = function->args_offset;
do {
+ /* GC: njs_retain(bound); */
*value++ = *bound++;
n--;
} while (n != 0);
@@ -134,8 +136,9 @@ njs_function_native_frame(njs_vm_t *vm,
nxt_noinline 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_function_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 size;
nxt_uint_t n, max_args;
diff -r 56d6fc12dc31 -r 2380d725ec7b njs/njs_function.h
--- a/njs/njs_function.h Wed Dec 07 15:02:00 2016 +0300
+++ b/njs/njs_function.h Wed Dec 07 19:34:48 2016 +0300
@@ -138,7 +138,8 @@ njs_ret_t njs_function_native_frame(njs_
const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs,
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);
+ const 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);
extern const njs_object_init_t njs_function_constructor_init;
diff -r 56d6fc12dc31 -r 2380d725ec7b njs/njs_vm.c
--- a/njs/njs_vm.c Wed Dec 07 15:02:00 2016 +0300
+++ b/njs/njs_vm.c Wed Dec 07 19:34:48 2016 +0300
@@ -82,9 +82,9 @@ static nxt_noinline njs_ret_t njs_values
const njs_value_t *val2);
static nxt_noinline njs_ret_t njs_values_compare(const njs_value_t *val1,
const njs_value_t *val2);
+static njs_ret_t njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
+ const njs_value_t *this, uintptr_t nargs, nxt_bool_t ctor);
static njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *value);
-static njs_ret_t njs_vmcode_method_call(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *value);
static njs_ret_t njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *invld2);
static njs_native_frame_t *
@@ -2127,61 +2127,58 @@ njs_ret_t
njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs)
{
njs_ret_t ret;
- nxt_bool_t ctor;
- njs_value_t val, *this;
- njs_object_t *object;
- njs_function_t *function;
- njs_vmcode_function_frame_t *func;
+ njs_vmcode_function_frame_t *function;
+
+ function = (njs_vmcode_function_frame_t *) vm->current;
+
+ /* TODO: external object instead of void this. */
+
+ ret = njs_function_frame_create(vm, value, &njs_value_void,
+ (uintptr_t) nargs, function->code.ctor);
+
+ if (nxt_fast_path(ret == NXT_OK)) {
+ return sizeof(njs_vmcode_function_frame_t);
+ }
+
+ return ret;
+}
+
+
+static njs_ret_t
+njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
+ const njs_value_t *this, uintptr_t nargs, nxt_bool_t ctor)
+{
+ njs_value_t val;
+ njs_object_t *object;
+ njs_function_t *function;
if (nxt_fast_path(njs_is_function(value))) {
- func = (njs_vmcode_function_frame_t *) vm->current;
- ctor = func->code.ctor;
-
function = value->data.u.function;
- if (function->native) {
- if (ctor && !function->ctor) {
- goto fail;
+ if (!function->native) {
+
+ if (ctor) {
+ object = njs_function_new_object(vm, value);
+ if (nxt_slow_path(object == NULL)) {
+ return NXT_ERROR;
+ }
+
+ val.data.u.object = object;
+ val.type = NJS_OBJECT;
+ val.data.truth = 1;
+ this = &val;
}
- ret = njs_function_native_frame(vm, function, &njs_value_void,
- NULL, (uintptr_t) nargs, 0, ctor);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_function_frame_t);
- }
-
- return ret;
+ return njs_function_frame(vm, function, this, NULL, nargs, ctor);
}
- if (ctor) {
- object = njs_function_new_object(vm, value);
- if (nxt_slow_path(object == NULL)) {
- return NXT_ERROR;
- }
-
- val.data.u.object = object;
- val.type = NJS_OBJECT;
- val.data.truth = 1;
- this = &val;
-
- } else {
- this = (njs_value_t *) &njs_value_void;
+ if (!ctor || function->ctor) {
+ return njs_function_native_frame(vm, function, this, NULL,
+ nargs, 0, ctor);
}
-
- ret = njs_function_frame(vm, function, this, NULL, (uintptr_t) nargs,
- ctor);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_function_frame_t);
- }
-
- return ret;
}
-fail:
-
vm->exception = &njs_exception_type_error;
return NXT_ERROR;
@@ -2237,6 +2234,8 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
njs_property_query_t pq;
njs_vmcode_method_frame_t *method;
+ method = (njs_vmcode_method_frame_t *) vm->current;
+
pq.query = NJS_PROPERTY_QUERY_GET;
switch (njs_property_query(vm, &pq, object, name)) {
@@ -2244,19 +2243,15 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
case NXT_OK:
prop = pq.lhq.value;
- if (njs_is_function(&prop->value)) {
- return njs_vmcode_method_call(vm, object, &prop->value);
- }
-
+ ret = njs_function_frame_create(vm, &prop->value, object, method->nargs,
+ method->code.ctor);
break;
case NJS_ARRAY_VALUE:
value = pq.lhq.value;
- if (njs_is_function(value)) {
- return njs_vmcode_method_call(vm, object, value);
- }
-
+ ret = njs_function_frame_create(vm, value, object, method->nargs,
+ method->code.ctor);
break;
case NJS_EXTERNAL_VALUE:
@@ -2264,67 +2259,37 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
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) {
- this.data.u.data = vm->external[ext->object];
-
- ret = njs_function_native_frame(vm, ext->function, &this, NULL,
- method->nargs, 0,
- method->code.ctor);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_method_frame_t);
- }
-
- return ret;
- }
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto type_error;
}
+
+ ext = pq.lhq.value;
+
+ if (nxt_slow_path(ext->type != NJS_EXTERN_METHOD)) {
+ goto type_error;
+ }
+
+ this.data.u.data = vm->external[ext->object];
+
+ ret = njs_function_native_frame(vm, ext->function, &this, NULL,
+ method->nargs, 0, method->code.ctor);
+ break;
+
+ default:
+ goto type_error;
}
- vm->exception = &njs_exception_type_error;
-
- return NXT_ERROR;
-}
-
-
-static njs_ret_t
-njs_vmcode_method_call(njs_vm_t *vm, njs_value_t *object, njs_value_t *value)
-{
- njs_ret_t ret;
- njs_function_t *function;
- njs_vmcode_method_frame_t *method;
-
- method = (njs_vmcode_method_frame_t *) vm->current;
- function = value->data.u.function;
-
- if (!function->native) {
- ret = njs_function_frame(vm, function, object, NULL, method->nargs,
- method->code.ctor);
-
- if (nxt_fast_path(ret == NXT_OK)) {
- return sizeof(njs_vmcode_method_frame_t);
- }
-
- return ret;
- }
-
- if (method->code.ctor) {
- vm->exception = &njs_exception_type_error;
- return NXT_ERROR;
- }
-
- ret = njs_function_native_frame(vm, function, object, NULL, method->nargs,
- 0, 0);
-
if (nxt_fast_path(ret == NXT_OK)) {
- njs_retain(object);
return sizeof(njs_vmcode_method_frame_t);
}
return ret;
+
+type_error:
+
+ vm->exception = &njs_exception_type_error;
+
+ return NXT_ERROR;
}
diff -r 56d6fc12dc31 -r 2380d725ec7b njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Wed Dec 07 15:02:00 2016 +0300
+++ b/njs/test/njs_unit_test.c Wed Dec 07 19:34:48 2016 +0300
@@ -4235,6 +4235,10 @@ static njs_unit_test_t njs_test[] =
"o.__proto__ === F.prototype"),
nxt_string("true") },
+ { nxt_string("f = { F: function(){} }; o = new f.F();"
+ "o.__proto__ === f.F.prototype"),
+ nxt_string("true") },
+
{ nxt_string("function F(){}; typeof F.prototype"),
nxt_string("object") },
More information about the nginx-devel
mailing list