]> git.kaiwu.me - njs.git/commitdiff
Fixed SetFunctionName() with Symbol keys.
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 9 Jul 2020 13:57:10 +0000 (13:57 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Thu, 9 Jul 2020 13:57:10 +0000 (13:57 +0000)
This improves 85c1b6ba326b.

src/njs_builtin.c
src/njs_function.c
src/njs_function.h
src/njs_json.c
src/njs_object.h
src/njs_object_prop.c
src/njs_string.c
src/njs_symbol.c
src/njs_symbol.h
src/test/njs_unit_test.c

index 3bf758ad79d20765d5937242ba22097480c69ba8..bd41b76b982a2b69466d22119add2381c340a562 100644 (file)
@@ -396,6 +396,7 @@ njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data)
     u_char                  *p, *start, *end;
     njs_int_t               ret, n;
     njs_str_t               name;
+    njs_bool_t              symbol;
     njs_value_t             key;
     njs_function_t          *func;
     njs_object_prop_t       *prop;
@@ -431,29 +432,37 @@ njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data)
     end = buf + sizeof(buf);
 
     do {
+        symbol = 0;
         key = path[n]->prop->name;
 
         if (njs_slow_path(njs_is_symbol(&key))) {
-            ret = njs_symbol_to_string(vm, &key, &key, 1);
-            if (njs_slow_path(ret != NJS_OK)) {
-                name = njs_str_value("#BROKEN_KEY");
-            }
-
-        } else {
-            if (p != buf) {
-                *p++ = '.';
+            symbol = 1;
+            key = *njs_symbol_description(&key);
+            if (njs_is_undefined(&key)) {
+                key = njs_string_empty;
             }
         }
 
         njs_string_get(&key, &name);
 
-        if (njs_slow_path((p + name.length + 1) > end)) {
+        if (njs_slow_path((p + name.length + 3) > end)) {
             njs_type_error(vm, "njs_builtin_traverse() key is too long");
             return NJS_ERROR;
         }
 
+        if (symbol) {
+            *p++ = '[';
+
+        } else if (p != buf) {
+            *p++ = '.';
+        }
+
         p = njs_cpymem(p, name.start, name.length);
 
+        if (symbol) {
+            *p++ = ']';
+        }
+
     } while (n-- > 0);
 
     if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) {
index 0898d5e4a725813c845d8bb4d3f386e3c19cea5c..5bd8fe922dbeb4ba85e230b8dbf2098a5331a536 100644 (file)
@@ -131,30 +131,53 @@ njs_function_active_closures(njs_vm_t *vm, njs_function_t *function)
 
 njs_int_t
 njs_function_name_set(njs_vm_t *vm, njs_function_t *function,
-    njs_value_t *name, njs_bool_t bound)
+    njs_value_t *name, const char *prefix)
 {
-    u_char              *start;
+    u_char              *p;
+    size_t              len, symbol;
     njs_int_t           ret;
+    njs_value_t         value;
     njs_string_prop_t   string;
     njs_object_prop_t   *prop;
     njs_lvlhsh_query_t  lhq;
 
     prop = njs_object_prop_alloc(vm, &njs_string_name, name, 0);
-    if (njs_slow_path(name == NULL)) {
+    if (njs_slow_path(prop == NULL)) {
         return NJS_ERROR;
     }
 
-    if (bound) {
-        (void) njs_string_prop(&string, name);
+    symbol = 0;
+
+    if (njs_is_symbol(&prop->value)) {
+        symbol = 2;
+        prop->value = *njs_symbol_description(&prop->value);
+    }
+
+    if (prefix != NULL || symbol != 0) {
+        value = prop->value;
+        (void) njs_string_prop(&string, &value);
 
-        start = njs_string_alloc(vm, &prop->value, string.size + 6,
-                                 string.length + 6);
-        if (njs_slow_path(start == NULL)) {
+        len = (prefix != NULL) ? njs_strlen(prefix) + 1: 0;
+        p = njs_string_alloc(vm, &prop->value, string.size + len + symbol,
+                             string.length + len + symbol);
+        if (njs_slow_path(p == NULL)) {
             return NJS_ERROR;
         }
 
-        start = njs_cpymem(start, "bound ", 6);
-        memcpy(start, string.start, string.size);
+        if (len != 0) {
+            p = njs_cpymem(p, prefix, len - 1);
+            *p++ = ' ';
+        }
+
+        if (symbol != 0) {
+            *p++ = '[';
+        }
+
+        p = njs_cpymem(p, string.start, string.size);
+
+        if (symbol != 0) {
+            *p++ = ']';
+        }
     }
 
     prop->configurable = 1;
@@ -1204,7 +1227,7 @@ njs_function_prototype_bind(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         name = njs_string_empty;
     }
 
-    ret = njs_function_name_set(vm, function, &name, 1);
+    ret = njs_function_name_set(vm, function, &name, "bound");
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
     }
index ce397a15b882a75b6630062124fa421c60e2fb4a..20cda0791beb2810da258b63fdb44c0f24e39c9d 100644 (file)
@@ -93,7 +93,7 @@ njs_function_t *njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda,
     njs_closure_t *closures[], njs_bool_t shared);
 njs_function_t *njs_function_value_copy(njs_vm_t *vm, njs_value_t *value);
 njs_int_t njs_function_name_set(njs_vm_t *vm, njs_function_t *function,
-    njs_value_t *name, njs_bool_t bound);
+    njs_value_t *name, const char *prefix);
 njs_int_t njs_function_arguments_object_init(njs_vm_t *vm,
     njs_native_frame_t *frame);
 njs_int_t njs_function_rest_parameters_init(njs_vm_t *vm,
index 68d3252580ebb2691f4b7386a9970def1bfa278e..8405add12e2b5bf4e47a2661ac51dc448db2ea5a 100644 (file)
@@ -1856,7 +1856,7 @@ njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
     case NJS_OBJECT_SYMBOL:
         value = njs_object_value(value);
 
-        ret = njs_symbol_to_string(stringify->vm, &str_val, value, 0);
+        ret = njs_symbol_descriptive_string(stringify->vm, &str_val, value);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -1867,7 +1867,7 @@ njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
         break;
 
     case NJS_SYMBOL:
-        ret = njs_symbol_to_string(stringify->vm, &str_val, value, 0);
+        ret = njs_symbol_descriptive_string(stringify->vm, &str_val, value);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
index 76ed32d0d42de90901f0e26631638faf635caf35..ddea784e9353b397bd79110b15b3d675d6079bc7 100644 (file)
@@ -213,7 +213,7 @@ njs_key_string_get(njs_vm_t *vm, njs_value_t *key, njs_str_t *str)
     njs_int_t  ret;
 
     if (njs_slow_path(njs_is_symbol(key))) {
-        ret = njs_symbol_to_string(vm, key, key, 0);
+        ret = njs_symbol_descriptive_string(vm, key, key);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
index 6c6340a48b200c3c1d7b766a7aec85654baa9e95..dc1aa2158e669af4074f78959528d2219caf3ff2 100644 (file)
@@ -554,7 +554,7 @@ njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
             return NJS_ERROR;
         }
 
-        return njs_function_name_set(vm, function, &prop->name, 0);
+        return njs_function_name_set(vm, function, &prop->name, NULL);
 
     default:
         break;
index e9e354122b485f040fb54647d2936cb240f15a1d..74c387e824b7e6fbdaf9911a17d12d4576df54e0 100644 (file)
@@ -486,7 +486,7 @@ njs_string_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         if (njs_slow_path(!njs_is_string(value))) {
             if (!vm->top_frame->ctor && njs_is_symbol(value)) {
-                return njs_symbol_to_string(vm, &vm->retval, value, 0);
+                return njs_symbol_descriptive_string(vm, &vm->retval, value);
             }
 
             ret = njs_value_to_string(vm, value, value);
index 9b704cc22dc03ad6f56099736754d3a3b818cd79..db262e791728b29a13d03c3f96e39eab69598446 100644 (file)
@@ -54,57 +54,53 @@ static const njs_value_t  *njs_symbol_names[NJS_SYMBOL_KNOWN_MAX] = {
 };
 
 
-njs_int_t
-njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *value,
-    njs_bool_t as_name)
+const njs_value_t *
+njs_symbol_description(const njs_value_t *value)
 {
-    u_char             *start;
     const njs_value_t  *name;
-    njs_string_prop_t  string;
-
-    static const njs_value_t  string_symbol = njs_string("Symbol()");
 
-    name = value->data.u.value;
+    if (njs_symbol_key(value) < NJS_SYMBOL_KNOWN_MAX) {
+        name = njs_symbol_names[njs_symbol_key(value)];
 
-    if (name == NULL) {
-        if (njs_fast_path(njs_symbol_key(value) < NJS_SYMBOL_KNOWN_MAX)) {
-
-            name = njs_symbol_names[njs_symbol_key(value)];
-
-        } else {
-            *dst = string_symbol;
+    } else {
+        name = value->data.u.value;
 
-            return NJS_OK;
+        if (name == NULL) {
+            return  &njs_value_undefined;
         }
     }
 
-    (void) njs_string_prop(&string, name);
+    return name;
+}
 
-    if (as_name) {
-        string.length += njs_length("[]");
 
-        start = njs_string_alloc(vm, dst, string.size + 2, string.length);
-        if (njs_slow_path(start == NULL)) {
-            return NJS_ERROR;
-        }
+njs_int_t
+njs_symbol_descriptive_string(njs_vm_t *vm, njs_value_t *dst,
+    const njs_value_t *value)
+{
+    u_char             *start;
+    const njs_value_t  *description;
+    njs_string_prop_t  string;
 
-        start = njs_cpymem(start, "[", 1);
-        start = njs_cpymem(start, string.start, string.size);
-        *start = ']';
+    description = njs_symbol_description(value);
 
-    } else {
-        string.length += njs_length("Symbol()");
+    if (njs_is_undefined(description)) {
+        description = &njs_string_empty;
+    }
 
-        start = njs_string_alloc(vm, dst, string.size + 8, string.length);
-        if (njs_slow_path(start == NULL)) {
-            return NJS_ERROR;
-        }
+    (void) njs_string_prop(&string, description);
 
-        start = njs_cpymem(start, "Symbol(", 7);
-        start = njs_cpymem(start, string.start, string.size);
-        *start = ')';
+    string.length += njs_length("Symbol()");
+
+    start = njs_string_alloc(vm, dst, string.size + 8, string.length);
+    if (njs_slow_path(start == NULL)) {
+        return NJS_ERROR;
     }
 
+    start = njs_cpymem(start, "Symbol(", 7);
+    start = njs_cpymem(start, string.start, string.size);
+    *start = ')';
+
     return NJS_OK;
 }
 
@@ -344,7 +340,7 @@ njs_symbol_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
         return ret;
     }
 
-    return njs_symbol_to_string(vm, &vm->retval, &vm->retval, 0);
+    return njs_symbol_descriptive_string(vm, &vm->retval, &vm->retval);
 }
 
 
@@ -352,28 +348,14 @@ static njs_int_t
 njs_symbol_prototype_description(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
-    njs_int_t          ret;
-    const njs_value_t  *value, *name;
+    njs_int_t  ret;
 
     ret = njs_symbol_prototype_value_of(vm, args, nargs, unused);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    value = &vm->retval;
-
-    name = value->data.u.value;
-
-    if (name == NULL) {
-        if (njs_fast_path(njs_symbol_key(value) < NJS_SYMBOL_KNOWN_MAX)) {
-            name = njs_symbol_names[njs_symbol_key(value)];
-
-        } else {
-            name = &njs_value_undefined;
-        }
-    }
-
-    vm->retval = *name;
+    vm->retval = *njs_symbol_description(&vm->retval);
 
     return NJS_OK;
 }
index 3b338b94b01731b362b817079f672084a12a0ae6..d722d2ff0ecb42ff3d7e20588f076ac3d3acaaa2 100644 (file)
@@ -7,8 +7,9 @@
 #ifndef _NJS_SYMBOL_H_INCLUDED_
 #define _NJS_SYMBOL_H_INCLUDED_
 
-njs_int_t njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst,
-    const njs_value_t *value, njs_bool_t as_name);
+const njs_value_t *njs_symbol_description(const njs_value_t *value);
+njs_int_t njs_symbol_descriptive_string(njs_vm_t *vm, njs_value_t *dst,
+    const njs_value_t *value);
 
 
 extern const njs_object_type_init_t  njs_symbol_type_init;
index d0b7e567396b142057b84e3ea4ced89bb6148a1d..65d0000cd4c06d9555c9d6b192e6d5708e6f573e 100644 (file)
@@ -6698,6 +6698,13 @@ static njs_unit_test_t  njs_test[] =
               "[f.name, f.bind().name]"),
       njs_str("F,bound F") },
 
+    { njs_str("var s = Symbol('F'); var f = Object.defineProperty(function() {}, 'name', {get:()=>s});"
+              "[f.name.description, f.bind().name]"),
+      njs_str("F,bound ") },
+
+    { njs_str("/a/[Symbol.replace].bind().name"),
+      njs_str("bound [Symbol.replace]") },
+
     { njs_str("var f = Object.defineProperty(function() {}, 'name', {get:()=>{throw Error('Oops')}});"
               "f.bind().name"),
       njs_str("Error: Oops") },
@@ -7736,6 +7743,9 @@ static njs_unit_test_t  njs_test[] =
               "'ABC'.replace(/(B)/, '$<g>')"),
       njs_str("OOps") },
 
+    { njs_str("var name = /a/g[Symbol.replace].name; [name, typeof name]"),
+      njs_str("[Symbol.replace],string") },
+
     { njs_str("RegExp.prototype[Symbol.replace].call()"),
       njs_str("TypeError: \"this\" is not object") },