]> git.kaiwu.me - njs.git/commitdiff
A user defined object method called as constructor did not
authorIgor Sysoev <igor@sysoev.ru>
Wed, 7 Dec 2016 16:34:48 +0000 (19:34 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Wed, 7 Dec 2016 16:34:48 +0000 (19:34 +0300)
create correct prototype links in created objects.

Thanks to 洪志道 (Hong Zhi Dao).

njs/njs_function.c
njs/njs_function.h
njs/njs_vm.c
njs/test/njs_unit_test.c

index 489a097dc01032736b39256b719313f11f588506..2153f0205353456a6957afbab528c0359df1375d 100644 (file)
@@ -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;
index f64b044a4d9bfd9136768967b47fd7921a78aae8..7320be3ed5a6733a89630a8b1b34e9f90c4125b2 100644 (file)
@@ -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;
index 9f92abbcb16e963676365a65b9f7b8b6a68fc9ab..68211728c3d3476633bdff3ea352d76ac0ee4f4d 100644 (file)
@@ -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;
 }
 
 
index 2de48b61d0552300c7fa15ae2b9db76a61581a05..fff872d81efefc5e412ed2ade0a27a523d4c17ac 100644 (file)
@@ -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") },