[njs] Refactored working with non-primitive types.

Dmitry Volyntsev xeioex at nginx.com
Fri Jul 19 20:28:15 UTC 2019


details:   https://hg.nginx.org/njs/rev/201af81dfa9b
branches:  
changeset: 1060:201af81dfa9b
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Jul 05 21:45:28 2019 +0300
description:
Refactored working with non-primitive types.

Traps mechanism is remove.

diffstat:

 njs/njs.c                       |     2 -
 njs/njs_array.c                 |    47 +-
 njs/njs_date.c                  |    31 +-
 njs/njs_function.c              |   108 ++-
 njs/njs_function.h              |    50 +-
 njs/njs_math.c                  |    24 +-
 njs/njs_object.c                |     2 -
 njs/njs_object_property.c       |    14 +-
 njs/njs_regexp.c                |    14 +-
 njs/njs_string.c                |    74 +-
 njs/njs_string.h                |     3 -
 njs/njs_value.c                 |   120 +-
 njs/njs_value.h                 |   137 ++-
 njs/njs_vm.c                    |  1451 ++++++++++++++++----------------------
 njs/njs_vm.h                    |    32 +-
 njs/test/njs_interactive_test.c |     3 +-
 njs/test/njs_unit_test.c        |    74 +
 17 files changed, 1033 insertions(+), 1153 deletions(-)

diffs (truncated from 3221 to 1000 lines):

diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs.c
--- a/njs/njs.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs.c	Fri Jul 05 21:45:28 2019 +0300
@@ -984,8 +984,6 @@ again:
 
         /* value evaluation threw an exception. */
 
-        vm->top_frame->trap_tries = 0;
-
         src = &vm->retval;
         goto again;
     }
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_array.c
--- a/njs/njs_array.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_array.c	Fri Jul 05 21:45:28 2019 +0300
@@ -528,10 +528,7 @@ njs_array_prototype_slice(njs_vm_t *vm, 
     ret = njs_value_property(vm, &args[0], &njs_string_length, &slice->length,
                              0);
 
-    if (nxt_slow_path(ret == NXT_ERROR
-                      || ret == NJS_TRAP
-                      || ret == NJS_APPLIED))
-    {
+    if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_APPLIED)) {
         return ret;
     }
 
@@ -544,13 +541,16 @@ njs_array_prototype_slice_continuation(n
     nxt_uint_t nargs, njs_index_t unused)
 {
     int64_t            start, end, length;
+    njs_ret_t          ret;
     njs_array_slice_t  *slice;
 
     slice = njs_vm_continuation(vm);
 
     if (nxt_slow_path(!njs_is_primitive(&slice->length))) {
-        njs_vm_trap_value(vm, &slice->length);
-        return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+        ret = njs_value_to_numeric(vm, &slice->length, &slice->length);
+        if (ret != NXT_OK) {
+            return ret;
+        }
     }
 
     start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
@@ -958,7 +958,7 @@ njs_array_prototype_reverse(njs_vm_t *vm
 
 static njs_ret_t
 njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
-    njs_index_t retval)
+    njs_index_t unused)
 {
     njs_object_prop_t   *prop;
     nxt_lvlhsh_query_t  lhq;
@@ -970,12 +970,12 @@ njs_array_prototype_to_string(njs_vm_t *
         prop = njs_object_property(vm, njs_object(&args[0]), &lhq);
 
         if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
-            return njs_function_replace(vm, njs_function(&prop->value),
-                                        args, nargs, retval);
+            return njs_function_call(vm, njs_function(&prop->value), args,
+                                     nargs, (njs_index_t) &vm->retval);
         }
     }
 
-    return njs_object_prototype_to_string(vm, args, nargs, retval);
+    return njs_object_prototype_to_string(vm, args, nargs, unused);
 }
 
 
@@ -1063,6 +1063,7 @@ njs_array_prototype_join_continuation(nj
     u_char             *p;
     size_t             size, length, mask;
     uint32_t           max;
+    njs_ret_t          ret;
     nxt_uint_t         i, n;
     njs_array_t        *array;
     njs_value_t        *value, *values;
@@ -1089,9 +1090,10 @@ njs_array_prototype_join_continuation(nj
                 value = &values[n++];
 
                 if (!njs_is_string(value)) {
-                    njs_vm_trap_value(vm, value);
-
-                    return njs_trap(vm, NJS_TRAP_STRING_ARG);
+                    ret = njs_value_to_string(vm, value, value);
+                    if (ret != NXT_OK) {
+                        return ret;
+                    }
                 }
             }
 
@@ -1442,10 +1444,7 @@ njs_array_prototype_fill(njs_vm_t *vm, n
         ret = njs_value_property(vm, this, &njs_string_length, &fill->length,
                                  0);
 
-        if (nxt_slow_path(ret == NXT_ERROR
-                          || ret == NJS_TRAP
-                          || ret == NJS_APPLIED))
-        {
+        if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_APPLIED)) {
             return ret;
         }
     }
@@ -1459,6 +1458,7 @@ njs_array_prototype_fill_continuation(nj
     nxt_uint_t nargs, njs_index_t unused)
 {
     nxt_int_t          i, start, end, length;
+    njs_ret_t          ret;
     njs_array_t        *array;
     njs_object_t       *object;
     njs_array_fill_t   *fill;
@@ -1488,8 +1488,10 @@ njs_array_prototype_fill_continuation(nj
     } else {
 
         if (nxt_slow_path(!njs_is_primitive(&fill->length))) {
-            njs_vm_trap_value(vm, &fill->length);
-            return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+            ret = njs_value_to_numeric(vm, &fill->length, &fill->length);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
 
         length = njs_primitive_value_to_length(&fill->length);
@@ -2202,9 +2204,10 @@ njs_array_string_sort(njs_vm_t *vm, njs_
 
     for (i = 1; i < nargs; i++) {
         if (!njs_is_string(&args[i])) {
-            njs_vm_trap_value(vm, &args[i]);
-
-            return njs_trap(vm, NJS_TRAP_STRING_ARG);
+            ret = njs_value_to_string(vm, &args[i], &args[i]);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
     }
 
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_date.c
--- a/njs/njs_date.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_date.c	Fri Jul 05 21:45:28 2019 +0300
@@ -73,6 +73,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v
 {
     double      num, time;
     int64_t     values[8];
+    njs_ret_t   ret;
     nxt_uint_t  i, n;
     njs_date_t  *date;
     struct tm   tm;
@@ -85,11 +86,14 @@ njs_date_constructor(njs_vm_t *vm, njs_v
         } else if (nargs == 2) {
             if (njs_is_object(&args[1])) {
                 if (!njs_is_date(&args[1])) {
-                    njs_vm_trap_value(vm, &args[1]);
-
-                    return njs_trap(vm, NJS_TRAP_PRIMITIVE_ARG);
+                    ret = njs_value_to_primitive(vm, &args[1], &args[1], 0);
+                    if (ret != NXT_OK) {
+                        return ret;
+                    }
                 }
-
+            }
+
+            if (njs_is_date(&args[1])) {
                 time = njs_date(&args[1])->time;
 
             } else if (njs_is_string(&args[1])) {
@@ -108,9 +112,10 @@ njs_date_constructor(njs_vm_t *vm, njs_v
 
             for (i = 1; i < n; i++) {
                 if (!njs_is_numeric(&args[i])) {
-                    njs_vm_trap_value(vm, &args[i]);
-
-                    return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+                    ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+                    if (ret != NXT_OK) {
+                        return ret;
+                    }
                 }
 
                 num = njs_number(&args[i]);
@@ -171,6 +176,7 @@ njs_date_utc(njs_vm_t *vm, njs_value_t *
 {
     double      num, time;
     struct tm   tm;
+    njs_ret_t   ret;
     nxt_uint_t  i, n;
     int32_t     values[8];
 
@@ -183,9 +189,10 @@ njs_date_utc(njs_vm_t *vm, njs_value_t *
 
         for (i = 1; i < n; i++) {
             if (!njs_is_numeric(&args[i])) {
-                njs_vm_trap_value(vm, &args[i]);
-
-                return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+                ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
 
             num = njs_number(&args[i]);
@@ -1902,8 +1909,8 @@ njs_date_prototype_to_json(njs_vm_t *vm,
         prop = njs_object_property(vm, njs_object(&args[0]), &lhq);
 
         if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
-            return njs_function_replace(vm, njs_function(&prop->value),
-                                        args, nargs, retval);
+            return njs_function_call(vm, njs_function(&prop->value), args,
+                                     nargs, (njs_index_t) &vm->retval);
         }
     }
 
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_function.c
--- a/njs/njs_function.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_function.c	Fri Jul 05 21:45:28 2019 +0300
@@ -473,6 +473,48 @@ njs_function_frame_alloc(njs_vm_t *vm, s
 
 
 njs_ret_t
+njs_function_call(njs_vm_t *vm, njs_function_t *function, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t retval)
+{
+    u_char              *return_address;
+    njs_ret_t           ret;
+    njs_native_frame_t  *frame;
+    njs_continuation_t  *cont;
+
+    ret = njs_function_frame(vm, function, &args[0], &args[1], nargs - 1, 0, 0);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
+
+    frame = vm->top_frame;
+    frame->call = 1;
+
+    return_address = vm->current;
+
+    if (function->native) {
+
+        if (function->continuation_size != 0) {
+            cont = njs_vm_continuation(vm);
+            cont->return_address = return_address;
+        }
+
+        ret = njs_function_native_call(vm, function->u.native, frame->arguments,
+                                       function->args_types, frame->nargs,
+                                       (njs_index_t) retval, return_address);
+
+    } else {
+        ret = njs_function_lambda_call(vm, retval, return_address);
+
+        if (nxt_fast_path(ret == NJS_APPLIED)) {
+            ret = njs_vmcode_run(vm);
+        }
+    }
+
+    return ret;
+}
+
+
+njs_ret_t
 njs_function_lambda_call(njs_vm_t *vm, njs_index_t retval,
     u_char *return_address)
 {
@@ -594,9 +636,9 @@ njs_function_native_call(njs_vm_t *vm, n
      * The callee arguments must be preserved
      * for NJS_APPLIED and NXT_AGAIN cases.
      */
-    if (ret == NXT_OK) {
-        frame = vm->top_frame;
+    frame = vm->top_frame;
 
+    if (ret == NXT_OK || (frame->call && ret == NXT_ERROR)) {
         vm->top_frame = njs_function_previous_frame(frame);
 
         /*
@@ -625,7 +667,7 @@ njs_function_native_call(njs_vm_t *vm, n
 
         njs_function_frame_free(vm, frame);
 
-        return NXT_OK;
+        return ret;
     }
 
     return ret;
@@ -636,8 +678,8 @@ static njs_ret_t
 njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types,
     nxt_uint_t nargs)
 {
+    njs_ret_t   ret;
     nxt_uint_t  n;
-    njs_trap_t  trap;
 
     n = nxt_min(nargs, NJS_ARGS_TYPES_MAX);
 
@@ -655,43 +697,47 @@ njs_normalize_args(njs_vm_t *vm, njs_val
 
         case NJS_STRING_ARG:
 
-            if (njs_is_string(args)) {
-                break;
+            if (!njs_is_string(args)) {
+                ret = njs_value_to_string(vm, args, args);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
 
-            trap = NJS_TRAP_STRING_ARG;
-            goto trap;
+            break;
 
         case NJS_NUMBER_ARG:
 
-            if (njs_is_numeric(args)) {
-                break;
+            if (!njs_is_numeric(args)) {
+                ret = njs_value_to_numeric(vm, args, args);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
 
-            trap = NJS_TRAP_NUMBER_ARG;
-            goto trap;
+            break;
 
         case NJS_INTEGER_ARG:
 
-            if (njs_is_numeric(args)) {
-
-                /* Numbers are truncated to fit in 32-bit integers. */
+            if (!njs_is_numeric(args)) {
+                ret = njs_value_to_numeric(vm, args, args);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
+            }
 
-                if (isnan(njs_number(args))) {
-                    njs_number(args) = 0;
+            /* Numbers are truncated to fit in 32-bit integers. */
 
-                } else if (njs_number(args) > 2147483647.0) {
+            if (!isnan(njs_number(args))) {
+                if (njs_number(args) > 2147483647.0) {
                     njs_number(args) = 2147483647.0;
 
                 } else if (njs_number(args) < -2147483648.0) {
                     njs_number(args) = -2147483648.0;
                 }
-
-                break;
             }
 
-            trap = NJS_TRAP_NUMBER_ARG;
-            goto trap;
+            break;
 
         case NJS_FUNCTION_ARG:
 
@@ -701,8 +747,10 @@ njs_normalize_args(njs_vm_t *vm, njs_val
                 break;
 
             default:
-                trap = NJS_TRAP_STRING_ARG;
-                goto trap;
+                ret = njs_value_to_string(vm, args, args);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
 
             break;
@@ -716,8 +764,10 @@ njs_normalize_args(njs_vm_t *vm, njs_val
                 break;
 
             default:
-                trap = NJS_TRAP_STRING_ARG;
-                goto trap;
+                ret = njs_value_to_string(vm, args, args);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
 
             break;
@@ -751,12 +801,6 @@ njs_normalize_args(njs_vm_t *vm, njs_val
 
     return NJS_OK;
 
-trap:
-
-    njs_vm_trap_value(vm, args);
-
-    return njs_trap(vm, trap);
-
 type_error:
 
     njs_type_error(vm, "cannot convert %s to %s", njs_type_string(args->type),
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_function.h
--- a/njs/njs_function.h	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_function.h	Fri Jul 05 21:45:28 2019 +0300
@@ -74,11 +74,6 @@ typedef struct {
 #define NJS_CONTINUATION_SIZE      njs_continuation_size(njs_continuation_t)
 
 
-#define njs_vm_trap_value(vm, val)                                            \
-    (vm)->top_frame->trap_scratch.data.u.value = val
-
-
-
 typedef struct njs_exception_s     njs_exception_t;
 
 struct njs_exception_s {
@@ -92,10 +87,6 @@ struct njs_exception_s {
 
 
 struct njs_native_frame_s {
-    njs_value_t                    trap_scratch;
-    njs_value_t                    trap_values[2];
-    u_char                         *trap_restart;
-
     u_char                         *free;
 
     njs_function_t                 *function;
@@ -118,14 +109,7 @@ struct njs_native_frame_s {
     /* Skip the Function.call() and Function.apply() methods frames. */
     uint8_t                        skip;              /* 1 bit  */
 
-    /* A number of trap tries, it can be no more than three. */
-    uint8_t                        trap_tries;        /* 2 bits */
-
-    /*
-     * The first operand in trap is reference to original value,
-     * it is used to increment or decrement this value.
-     */
-    uint8_t                        trap_reference;   /* 1 bit */
+    uint8_t                        call; /* 1 bit */
 };
 
 
@@ -168,6 +152,8 @@ njs_ret_t njs_function_lambda_frame(njs_
 njs_ret_t njs_function_activate(njs_vm_t *vm, njs_function_t *function,
     const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs,
     njs_index_t retval, size_t advance);
+njs_ret_t njs_function_call(njs_vm_t *vm, njs_function_t *function,
+    njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
 njs_ret_t njs_function_lambda_call(njs_vm_t *vm, njs_index_t retval,
     u_char *return_address);
 njs_ret_t njs_function_native_call(njs_vm_t *vm, njs_function_native_t native,
@@ -215,36 +201,6 @@ njs_function_apply(njs_vm_t *vm, njs_fun
 }
 
 
-/*
- * Replaces the current function with a new one.
- * Can only be used for continuation functions
- * (data.u.function.continuation_size > 0).
- */
-nxt_inline njs_ret_t
-njs_function_replace(njs_vm_t *vm, njs_function_t *function,
-    const njs_value_t *args, nxt_uint_t nargs, njs_index_t retval)
-{
-    nxt_int_t  ret;
-
-    ret = njs_function_apply(vm, function, args, nargs, retval);
-    if (nxt_slow_path(ret == NXT_ERROR)) {
-        return ret;
-    }
-
-    /*
-     * 1) njs_function_apply() allocs a new function frame,
-     *    in order to preserve the retval of a new function and ignore
-     *    retval of the current function during stack unwinding
-     *    skip flag is needed.
-     * 2) it is also needed for correct callee arguments update in
-     *    njs_function_native_call() see "Object((new Date(0)).toJSON())".
-     */
-    vm->top_frame->previous->skip = 1;
-
-    return NJS_APPLIED;
-}
-
-
 nxt_inline njs_native_frame_t *
 njs_function_previous_frame(njs_native_frame_t *frame)
 {
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_math.c
--- a/njs/njs_math.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_math.c	Fri Jul 05 21:45:28 2019 +0300
@@ -359,13 +359,15 @@ njs_object_math_hypot(njs_vm_t *vm, njs_
     njs_index_t unused)
 {
     double      num;
+    njs_ret_t   ret;
     nxt_uint_t  i;
 
     for (i = 1; i < nargs; i++) {
         if (!njs_is_numeric(&args[i])) {
-            njs_vm_trap_value(vm, &args[i]);
-
-            return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+            ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
     }
 
@@ -498,6 +500,7 @@ njs_object_math_max(njs_vm_t *vm, njs_va
     njs_index_t unused)
 {
     double      num;
+    njs_ret_t   ret;
     nxt_uint_t  i;
 
     if (nargs > 1) {
@@ -507,9 +510,10 @@ njs_object_math_max(njs_vm_t *vm, njs_va
                 goto done;
 
             } else if (!njs_is_numeric(&args[i])) {
-                njs_vm_trap_value(vm, &args[i]);
-
-                return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+                ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
         }
 
@@ -536,14 +540,16 @@ njs_object_math_min(njs_vm_t *vm, njs_va
     njs_index_t unused)
 {
     double      num;
+    njs_ret_t   ret;
     nxt_uint_t  i;
 
     if (nargs > 1) {
         for (i = 1; i < nargs; i++) {
             if (!njs_is_numeric(&args[i])) {
-                njs_vm_trap_value(vm, &args[i]);
-
-                return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+                ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+                if (ret != NXT_OK) {
+                    return ret;
+                }
             }
         }
 
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_object.c
--- a/njs/njs_object.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_object.c	Fri Jul 05 21:45:28 2019 +0300
@@ -2140,7 +2140,6 @@ njs_object_prototype_has_own_property(nj
         vm->retval = njs_value_false;
         return NXT_OK;
 
-    case NJS_TRAP:
     case NXT_ERROR:
     default:
         return ret;
@@ -2181,7 +2180,6 @@ njs_object_prototype_prop_is_enumerable(
         retval = &njs_value_false;
         break;
 
-    case NJS_TRAP:
     case NXT_ERROR:
     default:
         return ret;
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_object_property.c
--- a/njs/njs_object_property.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_object_property.c	Fri Jul 05 21:45:28 2019 +0300
@@ -38,7 +38,6 @@ static njs_object_prop_t *njs_descriptor
  *   NXT_DECLINED         property was not found in object,
  *     if pq->lhq.value != NULL it contains retval of type
  *     njs_object_prop_t * where prop->type is NJS_WHITEOUT
- *   NJS_TRAP             the property trap must be called,
  *   NXT_ERROR            exception has been thrown.
  *
  *   TODO:
@@ -53,10 +52,16 @@ njs_property_query(njs_vm_t *vm, njs_pro
     uint32_t        (*hash)(const void *, size_t);
     njs_ret_t       ret;
     njs_object_t    *obj;
+    njs_value_t     prop;
     njs_function_t  *function;
 
     if (nxt_slow_path(!njs_is_primitive(property))) {
-        return njs_trap(vm, NJS_TRAP_PROPERTY);
+        ret = njs_value_to_string(vm, &prop, (njs_value_t *) property);
+        if (ret != NXT_OK) {
+            return ret;
+        }
+
+        property = ∝
     }
 
     hash = nxt_djb_hash;
@@ -473,7 +478,6 @@ njs_external_property_delete(njs_vm_t *v
  *      retval will contain the property's value
  *
  *   NXT_DECLINED         property was not found in object
- *   NJS_TRAP             the property trap must be called
  *   NJS_APPLIED          the property getter was applied
  *   NXT_ERROR            exception has been thrown.
  *      retval will contain undefined
@@ -553,7 +557,6 @@ njs_value_property(njs_vm_t *vm, const n
 
         return NXT_DECLINED;
 
-    case NJS_TRAP:
     case NXT_ERROR:
     default:
 
@@ -566,7 +569,6 @@ njs_value_property(njs_vm_t *vm, const n
 
 /*
  *   NXT_OK               property has been set successfully
- *   NJS_TRAP             the property trap must be called
  *   NJS_APPLIED          the property setter was applied
  *   NXT_ERROR            exception has been thrown.
  */
@@ -669,7 +671,6 @@ njs_value_property_set(njs_vm_t *vm, njs
 
         break;
 
-    case NJS_TRAP:
     case NXT_ERROR:
     default:
 
@@ -1152,7 +1153,6 @@ njs_object_prop_descriptor(njs_vm_t *vm,
         *dest = njs_value_undefined;
         return NXT_OK;
 
-    case NJS_TRAP:
     case NXT_ERROR:
     default:
         return ret;
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_regexp.c
--- a/njs/njs_regexp.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_regexp.c	Fri Jul 05 21:45:28 2019 +0300
@@ -112,17 +112,19 @@ njs_regexp_constructor(njs_vm_t *vm, njs
     pattern = njs_arg(args, nargs, 1);
 
     if (!njs_is_regexp(pattern) && !njs_is_primitive(pattern)) {
-        njs_vm_trap_value(vm, &args[1]);
-
-        return njs_trap(vm, NJS_TRAP_STRING_ARG);
+        ret = njs_value_to_string(vm, &args[1], &args[1]);
+        if (ret != NXT_OK) {
+            return ret;
+        }
     }
 
     flags = njs_arg(args, nargs, 2);
 
     if (!njs_is_primitive(flags)) {
-        njs_vm_trap_value(vm, &args[2]);
-
-        return njs_trap(vm, NJS_TRAP_STRING_ARG);
+        ret = njs_value_to_string(vm, &args[2], &args[2]);
+        if (ret != NXT_OK) {
+            return ret;
+        }
     }
 
     re_flags = 0;
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_string.c
--- a/njs/njs_string.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_string.c	Fri Jul 05 21:45:28 2019 +0300
@@ -875,6 +875,7 @@ njs_string_prototype_concat(njs_vm_t *vm
 {
     u_char             *p, *start;
     uint64_t           size, length, mask;
+    njs_ret_t          ret;
     nxt_uint_t         i;
     njs_string_prop_t  string;
 
@@ -885,9 +886,10 @@ njs_string_prototype_concat(njs_vm_t *vm
 
     for (i = 0; i < nargs; i++) {
         if (!njs_is_string(&args[i])) {
-            njs_vm_trap_value(vm, &args[i]);
-
-            return njs_trap(vm, NJS_TRAP_STRING_ARG);
+            ret = njs_value_to_string(vm, &args[i], &args[i]);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
     }
 
@@ -1244,16 +1246,12 @@ njs_string_prototype_char_at(njs_vm_t *v
 
     slice.string_length = njs_string_prop(&string, &args[0]);
 
-    start = 0;
+    start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
     length = 1;
 
-    if (nargs > 1) {
-        start = njs_number(&args[1]);
-
-        if (start < 0 || start >= (ssize_t) slice.string_length) {
-            start = 0;
-            length = 0;
-        }
+    if (start < 0 || start >= (ssize_t) slice.string_length) {
+        start = 0;
+        length = 0;
     }
 
     slice.start = start;
@@ -1409,15 +1407,11 @@ njs_string_prototype_char_code_at(njs_vm
 
     length = njs_string_prop(&string, &args[0]);
 
-    index = 0;
-
-    if (nargs > 1) {
-        index = njs_number(&args[1]);
-
-        if (nxt_slow_path(index < 0 || index >= length)) {
-            num = NAN;
-            goto done;
-        }
+    index = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
+
+    if (nxt_slow_path(index < 0 || index >= length)) {
+        num = NAN;
+        goto done;
     }
 
     if ((uint32_t) length == string.size) {
@@ -1477,6 +1471,7 @@ njs_string_bytes_from_array(njs_vm_t *vm
 {
     u_char       *p;
     uint32_t     i, length;
+    njs_ret_t    ret;
     njs_array_t  *array;
     njs_value_t  *octet;
 
@@ -1485,9 +1480,10 @@ njs_string_bytes_from_array(njs_vm_t *vm
 
     for (i = 0; i < length; i++) {
         if (!njs_is_numeric(&array->start[i])) {
-            njs_vm_trap_value(vm, &array->start[i]);
-
-            return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+            ret = njs_value_to_numeric(vm, &array->start[i], &array->start[i]);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
     }
 
@@ -1713,13 +1709,15 @@ njs_string_from_char_code(njs_vm_t *vm, 
     double      num;
     size_t      size;
     int32_t     code;
+    njs_ret_t   ret;
     nxt_uint_t  i;
 
     for (i = 1; i < nargs; i++) {
         if (!njs_is_numeric(&args[i])) {
-            njs_vm_trap_value(vm, &args[i]);
-
-            return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
+            ret = njs_value_to_numeric(vm, &args[i], &args[i]);
+            if (ret != NXT_OK) {
+                return ret;
+            }
         }
     }
 
@@ -2426,20 +2424,16 @@ njs_string_prototype_repeat(njs_vm_t *vm
     uint32_t           size, length;
     njs_string_prop_t  string;
 
-    n = 0;
+    n = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
 
     (void) njs_string_prop(&string, &args[0]);
 
-    if (nargs > 1) {
-        max = (string.size > 1) ? NJS_STRING_MAX_LENGTH / string.size
-                                : NJS_STRING_MAX_LENGTH;
-
-        n = njs_number(&args[1]);
-
-        if (nxt_slow_path(n < 0 || n >= max)) {
-            njs_range_error(vm, NULL);
-            return NXT_ERROR;
-        }
+    max = (string.size > 1) ? NJS_STRING_MAX_LENGTH / string.size
+                            : NJS_STRING_MAX_LENGTH;
+
+    if (nxt_slow_path(n < 0 || n >= max)) {
+        njs_range_error(vm, NULL);
+        return NXT_ERROR;
     }
 
     if (string.size == 0) {
@@ -3427,8 +3421,10 @@ njs_string_replace_search_continuation(n
     r = njs_vm_continuation(vm);
 
     if (!njs_is_primitive(&r->retval)) {
-        njs_vm_trap_value(vm, &r->retval);
-        return njs_trap(vm, NJS_TRAP_STRING_ARG);
+        ret = njs_value_to_string(vm, &r->retval, &r->retval);
+        if (ret != NXT_OK) {
+            return ret;
+        }
     }
 
     ret = njs_primitive_value_to_string(vm, &string, &r->retval);
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_string.h
--- a/njs/njs_string.h	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_string.h	Fri Jul 05 21:45:28 2019 +0300
@@ -177,10 +177,7 @@ const u_char *njs_string_offset(const u_
     size_t index);
 uint32_t njs_string_index(njs_string_prop_t *string, uint32_t offset);
 void njs_string_offset_map_init(const u_char *start, size_t size);
-njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
-    const njs_value_t *src);
 double njs_string_to_index(const njs_value_t *value);
-double njs_string_to_number(const njs_value_t *value, nxt_bool_t parse_float);
 const u_char *njs_string_to_c_string(njs_vm_t *vm, njs_value_t *value);
 njs_ret_t njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_value.c
--- a/njs/njs_value.c	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_value.c	Fri Jul 05 21:45:28 2019 +0300
@@ -101,14 +101,16 @@ njs_value_release(njs_vm_t *vm, njs_valu
  */
 
 njs_ret_t
-njs_value_to_primitive(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint)
+njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value,
+	nxt_uint_t hint)
 {
     njs_ret_t           ret;
-    njs_value_t         *retval;
-    njs_function_t      *function;
+    nxt_uint_t          tries;
     njs_object_prop_t   *prop;
     nxt_lvlhsh_query_t  lhq;
 
+    njs_value_t         retval nxt_aligned(16);
+
     static const uint32_t  hashes[] = {
         NJS_VALUE_OF_HASH,
         NJS_TO_STRING_HASH,
@@ -119,76 +121,56 @@ njs_value_to_primitive(njs_vm_t *vm, njs
         nxt_string("toString"),
     };
 
-    if (!njs_is_primitive(value)) {
-        retval = &vm->top_frame->trap_scratch;
 
-        if (!njs_is_primitive(retval)) {
-
-            for ( ;; ) {
-                ret = NXT_ERROR;
-
-                if (njs_is_object(value) && vm->top_frame->trap_tries < 2) {
-                    hint ^= vm->top_frame->trap_tries++;
-
-                    lhq.key_hash = hashes[hint];
-                    lhq.key = names[hint];
-
-                    prop = njs_object_property(vm, njs_object(value), &lhq);
-
-                    if (nxt_fast_path(prop != NULL)) {
-
-                        if (!njs_is_function(&prop->value)) {
-                            /* Try the second method. */
-                            continue;
-                        }
-
-                        function = njs_function(&prop->value);
-
-                        ret = njs_function_apply(vm, function, value, 1,
-                                                 (njs_index_t) retval);
-                        /*
-                         * njs_function_apply() can return
-                         *   NXT_OK, NJS_APPLIED, NXT_ERROR, NXT_AGAIN.
-                         */
-                        if (nxt_fast_path(ret == NXT_OK)) {
-
-                            if (njs_is_primitive(&vm->retval)) {
-                                retval = &vm->retval;
-                                break;
-                            }
-
-                            /* Try the second method. */
-                            continue;
-                        }
-
-                        if (ret == NJS_APPLIED) {
-                            /*
-                             * A user-defined method or continuation have
-                             * been prepared to run.  The method will return
-                             * to the current instruction and will restart it.
-                             */
-                            ret = 0;
-                        }
-                    }
-                }
-
-                if (ret == NXT_ERROR) {
-                    njs_type_error(vm,
-                                   "Cannot convert object to primitive value");
-                }
-
-                return ret;
-            }
-        }
-
-        *value = *retval;
-
-        njs_set_invalid(retval);
+    if (njs_is_primitive(value)) {
+        /* GC */
+        *dst = *value;
+        return NXT_OK;
     }
 
-    vm->top_frame->trap_tries = 0;
+    tries = 0;
+
+    for ( ;; ) {
+        ret = NXT_ERROR;
+
+        if (njs_is_object(value) && tries < 2) {
+            hint ^= tries++;
+
+            lhq.key_hash = hashes[hint];
+            lhq.key = names[hint];
+
+            prop = njs_object_property(vm, njs_object(value), &lhq);
+
+            if (prop == NULL || !njs_is_function(&prop->value)) {
+                /* Try the second method. */
+                continue;
+            }
+
+            ret = njs_function_call(vm, njs_function(&prop->value), value, 1,
+                                    (njs_index_t) &retval);
 
-    return 1;
+            if (nxt_fast_path(ret == NXT_OK)) {
+                if (njs_is_primitive(&retval)) {
+                    break;
+                 }
+
+                /* Try the second method. */
+                continue;
+             }
+
+            /* NXT_ERROR */
+
+            return ret;
+         }
+
+        njs_type_error(vm, "Cannot convert object to primitive value");
+
+        return ret;
+    }
+
+    *dst = retval;
+
+    return NXT_OK;
 }
 
 
diff -r 2fdad3cbbd74 -r 201af81dfa9b njs/njs_value.h
--- a/njs/njs_value.h	Thu Jul 18 21:12:25 2019 +0300
+++ b/njs/njs_value.h	Fri Jul 05 21:45:28 2019 +0300
@@ -114,6 +114,9 @@ typedef struct njs_date_s             nj
 typedef struct njs_property_next_s    njs_property_next_t;
 typedef struct njs_object_init_s      njs_object_init_t;
 
+#if (!NXT_HAVE_GCC_ATTRIBUTE_ALIGNED)
+#error "aligned attribute is required"
+#endif
 
 union njs_value_s {
     /*
@@ -560,10 +563,6 @@ typedef enum {
     *(value) = njs_value_undefined
 
 


More information about the nginx-devel mailing list