From dfd9cacbd11727404f7b9d1860b218167713db5a Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Wed, 7 Dec 2016 19:34:48 +0300 Subject: [PATCH] A user defined object method called as constructor did not create correct prototype links in created objects. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Thanks to 洪志道 (Hong Zhi Dao). --- njs/njs_function.c | 7 +- njs/njs_function.h | 3 +- njs/njs_vm.c | 159 +++++++++++++++------------------------ njs/test/njs_unit_test.c | 4 + 4 files changed, 73 insertions(+), 100 deletions(-) diff --git a/njs/njs_function.c b/njs/njs_function.c index 489a097d..2153f020 100644 --- a/njs/njs_function.c +++ b/njs/njs_function.c @@ -111,12 +111,14 @@ njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, 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, njs_function_t *function, 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 --git a/njs/njs_function.h b/njs/njs_function.h index f64b044a..7320be3e 100644 --- a/njs/njs_function.h +++ b/njs/njs_function.h @@ -138,7 +138,8 @@ 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, 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 --git a/njs/njs_vm.c b/njs/njs_vm.c index 9f92abbc..68211728 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -82,9 +82,9 @@ static nxt_noinline njs_ret_t njs_values_equal(const njs_value_t *val1, 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; - if (nxt_fast_path(njs_is_function(value))) { + function = (njs_vmcode_function_frame_t *) vm->current; - func = (njs_vmcode_function_frame_t *) vm->current; - ctor = func->code.ctor; + /* TODO: external object instead of void this. */ - function = value->data.u.function; + ret = njs_function_frame_create(vm, value, &njs_value_void, + (uintptr_t) nargs, function->code.ctor); - if (function->native) { - if (ctor && !function->ctor) { - goto fail; - } + if (nxt_fast_path(ret == NXT_OK)) { + return sizeof(njs_vmcode_function_frame_t); + } - ret = njs_function_native_frame(vm, function, &njs_value_void, - NULL, (uintptr_t) nargs, 0, ctor); + return ret; +} - 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 (ctor) { - object = njs_function_new_object(vm, value); - if (nxt_slow_path(object == NULL)) { - return NXT_ERROR; - } + if (nxt_fast_path(njs_is_function(value))) { - val.data.u.object = object; - val.type = NJS_OBJECT; - val.data.truth = 1; - this = &val; + function = value->data.u.function; - } else { - this = (njs_value_t *) &njs_value_void; - } + if (!function->native) { - ret = njs_function_frame(vm, function, this, NULL, (uintptr_t) nargs, - ctor); + if (ctor) { + object = njs_function_new_object(vm, value); + if (nxt_slow_path(object == NULL)) { + return NXT_ERROR; + } - if (nxt_fast_path(ret == NXT_OK)) { - return sizeof(njs_vmcode_function_frame_t); + val.data.u.object = object; + val.type = NJS_OBJECT; + val.data.truth = 1; + this = &val; + } + + return njs_function_frame(vm, function, this, NULL, nargs, ctor); } - return ret; + if (!ctor || function->ctor) { + return njs_function_native_frame(vm, function, this, NULL, + nargs, 0, ctor); + } } -fail: - vm->exception = &njs_exception_type_error; return NXT_ERROR; @@ -2237,6 +2234,8 @@ njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name) 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, njs_value_t *object, njs_value_t *name) 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, njs_value_t *object, njs_value_t *name) 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; } - } - - 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; + ext = pq.lhq.value; - 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); + if (nxt_slow_path(ext->type != NJS_EXTERN_METHOD)) { + goto type_error; } - return ret; - } + this.data.u.data = vm->external[ext->object]; - if (method->code.ctor) { - vm->exception = &njs_exception_type_error; - return NXT_ERROR; - } + ret = njs_function_native_frame(vm, ext->function, &this, NULL, + method->nargs, 0, method->code.ctor); + break; - ret = njs_function_native_frame(vm, function, object, NULL, method->nargs, - 0, 0); + default: + goto type_error; + } 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 --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 2de48b61..fff872d8 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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") }, -- 2.47.3