[njs] Added Object.setPrototypeOf().

Dmitry Volyntsev xeioex at nginx.com
Fri Nov 29 14:28:31 UTC 2019


details:   https://hg.nginx.org/njs/rev/01c7375c9b5c
branches:  
changeset: 1271:01c7375c9b5c
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Fri Nov 29 12:53:33 2019 +0300
description:
Added Object.setPrototypeOf().

This closes #265 issue on Github.

diffstat:

 src/njs_object.c         |  61 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/test/njs_unit_test.c |  35 +++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 2 deletions(-)

diffs (144 lines):

diff -r e20023dd991d -r 01c7375c9b5c src/njs_object.c
--- a/src/njs_object.c	Fri Nov 29 17:11:11 2019 +0300
+++ b/src/njs_object.c	Fri Nov 29 12:53:33 2019 +0300
@@ -30,6 +30,8 @@ static njs_int_t njs_object_own_enumerat
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
 static njs_int_t njs_object_define_properties(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_object_set_prototype(njs_vm_t *vm, njs_object_t *object,
+    const njs_value_t *value);
 
 
 njs_object_t *
@@ -1476,6 +1478,52 @@ njs_object_get_prototype_of(njs_vm_t *vm
 
 
 static njs_int_t
+njs_object_set_prototype_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_int_t    ret;
+    njs_value_t  *value, *proto;
+
+    value = njs_arg(args, nargs, 1);
+    if (njs_slow_path(njs_is_null_or_undefined(value))) {
+        njs_type_error(vm, "cannot convert %s argument to object",
+                       njs_type_string(value->type));
+        return NJS_ERROR;
+    }
+
+    proto = njs_arg(args, nargs, 2);
+    if (njs_slow_path(!njs_is_object(proto) && !njs_is_null(proto))) {
+        njs_type_error(vm, "prototype may only be an object or null: %s",
+                       njs_type_string(proto->type));
+        return NJS_ERROR;
+    }
+
+    if (njs_slow_path(!njs_is_object(value))) {
+        vm->retval = *value;
+
+        return NJS_OK;
+    }
+
+    ret = njs_object_set_prototype(vm, njs_object(value), proto);
+    if (njs_fast_path(ret == NJS_OK)) {
+        vm->retval = *value;
+
+        return NJS_OK;
+    }
+
+    if (ret == NJS_DECLINED) {
+        njs_type_error(vm, "Cannot set property \"prototype\", "
+                       "object is not extensible");
+
+    } else {
+        njs_type_error(vm, "Cyclic __proto__ value");
+    }
+
+    return NJS_ERROR;
+}
+
+
+static njs_int_t
 njs_object_freeze(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
@@ -2011,6 +2059,15 @@ static const njs_object_prop_t  njs_obje
         .configurable = 1,
     },
 
+    /* Object.setPrototypeOf(). */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setPrototypeOf"),
+        .value = njs_native_function(njs_object_set_prototype_of, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
+
     /* Object.freeze(). */
     {
         .type = NJS_PROPERTY,
@@ -2095,7 +2152,7 @@ const njs_object_init_t  njs_object_cons
  * ES6, 9.1.2: [[SetPrototypeOf]].
  */
 static njs_int_t
-njs_object_set_prototype_of(njs_vm_t *vm, njs_object_t *object,
+njs_object_set_prototype(njs_vm_t *vm, njs_object_t *object,
     const njs_value_t *value)
 {
     const njs_object_t *proto;
@@ -2146,7 +2203,7 @@ njs_object_prototype_proto(njs_vm_t *vm,
 
     if (setval != NULL) {
         if (njs_is_object(setval) || njs_is_null(setval)) {
-            ret = njs_object_set_prototype_of(vm, object, setval);
+            ret = njs_object_set_prototype(vm, object, setval);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 njs_type_error(vm, "Cyclic __proto__ value");
                 return NJS_ERROR;
diff -r e20023dd991d -r 01c7375c9b5c src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Nov 29 17:11:11 2019 +0300
+++ b/src/test/njs_unit_test.c	Fri Nov 29 12:53:33 2019 +0300
@@ -11527,6 +11527,41 @@ static njs_unit_test_t  njs_test[] =
               ".every((x) => Object.getPrototypeOf(x) == Object.getPrototypeOf(Object(x)))"),
       njs_str("true") },
 
+    /* Object.setPrototypeOf() */
+
+    { njs_str("Object.setPrototypeOf()"),
+      njs_str("TypeError: cannot convert undefined argument to object") },
+
+    { njs_str("Object.setPrototypeOf(null)"),
+      njs_str("TypeError: cannot convert null argument to object") },
+
+    { njs_str("Object.setPrototypeOf({})"),
+      njs_str("TypeError: prototype may only be an object or null: undefined") },
+
+    { njs_str("Object.setPrototypeOf(Object.preventExtensions({}))"),
+      njs_str("TypeError: prototype may only be an object or null: undefined") },
+
+    { njs_str("[true, 42, '', Symbol()]"
+              ".every((x) => Object.setPrototypeOf(x, {}) === x)"),
+      njs_str("true") },
+
+    { njs_str("Object.setPrototypeOf(Object.preventExtensions({}), {})"),
+      njs_str("TypeError: Cannot set property \"prototype\", object is not extensible") },
+
+    { njs_str("var p = {}, o = Object.create(p); Object.setPrototypeOf(p, o)"),
+      njs_str("TypeError: Cyclic __proto__ value") },
+
+    { njs_str("var p = {}, o = {}; Object.setPrototypeOf(o, p);"
+              "p.isPrototypeOf(o)"),
+      njs_str("true") },
+
+    { njs_str("var p = {}, o = Object.create(p); Object.setPrototypeOf(o, null);"
+              "Object.getPrototypeOf(o)"),
+      njs_str("null") },
+
+    { njs_str("typeof Object.setPrototypeOf({}, null)"),
+      njs_str("object") },
+
     { njs_str("var p = {}; var o = Object.create(p);"
                  "p.isPrototypeOf(o)"),
       njs_str("true") },


More information about the nginx-devel mailing list