[njs] Added fast path in [[Get]] and [[Set]] for arrays and typed-arrays.

Dmitry Volyntsev xeioex at nginx.com
Tue Feb 4 17:35:26 UTC 2020


details:   https://hg.nginx.org/njs/rev/f5afb325896f
branches:  
changeset: 1315:f5afb325896f
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Feb 04 20:35:00 2020 +0300
description:
Added fast path in [[Get]] and [[Set]] for arrays and typed-arrays.

diffstat:

 src/njs_array.c          |    1 +
 src/njs_number.h         |   12 ++++-
 src/njs_object.c         |    3 +
 src/njs_typed_array.c    |    1 +
 src/njs_value.c          |  108 +++++++++++++++++++++++++++++++++++++++++++++-
 src/njs_value.h          |    1 +
 src/njs_vmcode.c         |    2 +-
 src/test/njs_unit_test.c |    4 +-
 8 files changed, 123 insertions(+), 9 deletions(-)

diffs (276 lines):

diff -r 2b75ee955589 -r f5afb325896f src/njs_array.c
--- a/src/njs_array.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_array.c	Tue Feb 04 20:35:00 2020 +0300
@@ -67,6 +67,7 @@ njs_array_alloc(njs_vm_t *vm, uint64_t l
     array->object.type = NJS_ARRAY;
     array->object.shared = 0;
     array->object.extensible = 1;
+    array->object.fast_array = 1;
     array->size = size;
     array->length = length;
 
diff -r 2b75ee955589 -r f5afb325896f src/njs_number.h
--- a/src/njs_number.h	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_number.h	Tue Feb 04 20:35:00 2020 +0300
@@ -30,16 +30,24 @@ njs_int_t njs_number_parse_float(njs_vm_
 
 
 njs_inline njs_bool_t
-njs_number_is_integer_index(double num, const njs_value_t *value)
+njs_number_is_integer_index(double num)
 {
     uint32_t  u32;
 
     u32 = num;
 
-    return (u32 == num && u32 != 0xffffffff)
+    return (u32 == num && u32 != 0xffffffff);
+}
+
+
+njs_inline njs_bool_t
+njs_key_is_integer_index(double num, const njs_value_t *value)
+{
+    return (njs_number_is_integer_index(num))
             && !(njs_is_string(value) && num == 0 && signbit(num));
 }
 
+
 njs_inline int64_t
 njs_number_to_int64(double num)
 {
diff -r 2b75ee955589 -r f5afb325896f src/njs_object.c
--- a/src/njs_object.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_object.c	Tue Feb 04 20:35:00 2020 +0300
@@ -51,6 +51,8 @@ njs_object_alloc(njs_vm_t *vm)
         object->shared = 0;
         object->extensible = 1;
         object->error_data = 0;
+        object->fast_array = 0;
+
         return object;
     }
 
@@ -108,6 +110,7 @@ njs_object_value_alloc(njs_vm_t *vm, con
         ov->object.type = njs_object_value_type(type);
         ov->object.shared = 0;
         ov->object.extensible = 1;
+        ov->object.fast_array = 0;
 
         index = njs_primitive_prototype_index(type);
         ov->object.__proto__ = &vm->prototypes[index].object;
diff -r 2b75ee955589 -r f5afb325896f src/njs_typed_array.c
--- a/src/njs_typed_array.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_typed_array.c	Tue Feb 04 20:35:00 2020 +0300
@@ -179,6 +179,7 @@ njs_typed_array_constructor(njs_vm_t *vm
     array->object.type = NJS_TYPED_ARRAY;
     array->object.shared = 0;
     array->object.extensible = 1;
+    array->object.fast_array = 1;
 
     njs_set_typed_array(&vm->retval, array);
 
diff -r 2b75ee955589 -r f5afb325896f src/njs_value.c
--- a/src/njs_value.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_value.c	Tue Feb 04 20:35:00 2020 +0300
@@ -549,7 +549,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
     case NJS_STRING:
         if (njs_fast_path(!njs_is_null_or_undefined_or_boolean(key))) {
             num = njs_key_to_index(key);
-            if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+            if (njs_fast_path(njs_key_is_integer_index(num, key))) {
                 return njs_string_property_query(vm, pq, value, num);
             }
         }
@@ -654,7 +654,7 @@ njs_object_property_query(njs_vm_t *vm, 
             switch (proto->type) {
             case NJS_ARRAY:
                 num = njs_key_to_index(key);
-                if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+                if (njs_fast_path(njs_key_is_integer_index(num, key))) {
                     array = (njs_array_t *) proto;
                     return njs_array_property_query(vm, pq, array, num);
                 }
@@ -663,7 +663,7 @@ njs_object_property_query(njs_vm_t *vm, 
 
             case NJS_TYPED_ARRAY:
                 num = njs_key_to_index(key);
-                if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+                if (njs_fast_path(njs_key_is_integer_index(num, key))) {
                     tarray = (njs_typed_array_t *) proto;
                     return njs_typed_array_property_query(vm, pq, tarray, num);
                 }
@@ -676,7 +676,7 @@ njs_object_property_query(njs_vm_t *vm, 
 
             case NJS_OBJECT_STRING:
                 num = njs_key_to_index(key);
-                if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+                if (njs_fast_path(njs_key_is_integer_index(num, key))) {
                     ov = (njs_object_value_t *) proto;
                     ret = njs_string_property_query(vm, pq, &ov->value, num);
 
@@ -1021,10 +1021,60 @@ njs_int_t
 njs_value_property(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
     njs_value_t *retval)
 {
+    double                num;
+    uint32_t              index;
     njs_int_t             ret;
+    njs_array_t          *array;
     njs_object_prop_t     *prop;
+    njs_typed_array_t     *tarray;
     njs_property_query_t  pq;
 
+    if (njs_fast_path(njs_is_number(key))) {
+        num = njs_number(key);
+
+        if (njs_slow_path(!njs_number_is_integer_index(num))) {
+            goto slow_path;
+        }
+
+        index = (uint32_t) num;
+
+        if (njs_is_typed_array(value)) {
+            tarray = njs_typed_array(value);
+
+            if (njs_slow_path(index >= njs_typed_array_length(tarray))) {
+                goto slow_path;
+            }
+
+            njs_set_number(retval, njs_typed_array_get(tarray, index));
+
+            return NJS_OK;
+        }
+
+        if (njs_slow_path(!(njs_is_object(value)
+                            && njs_object(value)->fast_array)))
+        {
+            goto slow_path;
+        }
+
+        /* NJS_ARRAY */
+
+        array = njs_array(value);
+
+        if (njs_slow_path(index >= array->length)) {
+            goto slow_path;
+        }
+
+        *retval = array->start[index];
+
+        if (njs_slow_path(!njs_is_valid(retval))) {
+            njs_set_undefined(retval);
+        }
+
+        return NJS_OK;
+    }
+
+slow_path:
+
     njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
 
     ret = njs_property_query(vm, &pq, value, key);
@@ -1093,16 +1143,66 @@ njs_int_t
 njs_value_property_set(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
     njs_value_t *setval)
 {
+    double                num;
+    uint32_t              index;
     njs_int_t             ret;
+    njs_array_t           *array;
     njs_object_prop_t     *prop;
+    njs_typed_array_t     *tarray;
     njs_property_query_t  pq;
 
+    if (njs_fast_path(njs_is_number(key))) {
+        num = njs_number(key);
+
+        if (njs_slow_path(!njs_number_is_integer_index(num))) {
+            goto slow_path;
+        }
+
+        index = (uint32_t) num;
+
+        if (njs_is_typed_array(value)) {
+            tarray = njs_typed_array(value);
+
+            if (njs_fast_path(index < njs_typed_array_length(tarray))) {
+                ret = njs_value_to_number(vm, setval, &num);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return ret;
+                }
+
+                njs_typed_array_set(tarray, index, num);
+            }
+
+            return NJS_OK;
+        }
+
+        if (njs_slow_path(!(njs_is_object(value)
+                            && njs_object(value)->fast_array)))
+        {
+            goto slow_path;
+        }
+
+        /* NJS_ARRAY */
+
+        array = njs_array(value);
+
+        if (njs_slow_path(index >= array->length)) {
+            goto slow_path;
+        }
+
+        array->start[index] = *setval;
+
+        return NJS_OK;
+    }
+
+slow_path:
+
     if (njs_is_primitive(value)) {
         njs_type_error(vm, "property set on primitive %s type",
                        njs_type_string(value->type));
         return NJS_ERROR;
     }
 
+
     njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);
 
     ret = njs_property_query(vm, &pq, value, key);
diff -r 2b75ee955589 -r f5afb325896f src/njs_value.h
--- a/src/njs_value.h	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_value.h	Tue Feb 04 20:35:00 2020 +0300
@@ -215,6 +215,7 @@ struct njs_object_s {
 
     uint8_t                           extensible:1;
     uint8_t                           error_data:1;
+    uint8_t                           fast_array:1;
 };
 
 
diff -r 2b75ee955589 -r f5afb325896f src/njs_vmcode.c
--- a/src/njs_vmcode.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/njs_vmcode.c	Tue Feb 04 20:35:00 2020 +0300
@@ -1152,7 +1152,7 @@ njs_vmcode_property_init(njs_vm_t *vm, n
     switch (value->type) {
     case NJS_ARRAY:
         num = njs_key_to_index(key);
-        if (njs_slow_path(!njs_number_is_integer_index(num, key))) {
+        if (njs_slow_path(!njs_key_is_integer_index(num, key))) {
             njs_internal_error(vm,
                                "invalid index while property initialization");
             return NJS_ERROR;
diff -r 2b75ee955589 -r f5afb325896f src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Mon Jan 20 13:24:09 2020 +0300
+++ b/src/test/njs_unit_test.c	Tue Feb 04 20:35:00 2020 +0300
@@ -17772,8 +17772,8 @@ njs_string_to_index_test(njs_vm_t *vm, n
             }
         }
 
-        is_integer_index = njs_number_is_integer_index(njs_number(&vm->retval),
-                                                       &tests[i].value);
+        is_integer_index = njs_key_is_integer_index(njs_number(&vm->retval),
+                                                    &tests[i].value);
 
         if (tests[i].is_integer_index != is_integer_index) {
             njs_string_get(&tests[i].value, &string);


More information about the nginx-devel mailing list