[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