[njs] Moving value methods to njs_value.c.

Dmitry Volyntsev xeioex at nginx.com
Mon Jul 8 12:46:39 UTC 2019


details:   https://hg.nginx.org/njs/rev/5c774a8c8332
branches:  
changeset: 1031:5c774a8c8332
user:      hongzhidao <hongzhidao at gmail.com>
date:      Sat Jul 06 10:27:14 2019 -0400
description:
Moving value methods to njs_value.c.

diffstat:

 auto/sources    |    1 +
 njs/njs_core.h  |    1 +
 njs/njs_value.c |  418 +++++++++++++++++++++++++++++++++++
 njs/njs_value.h |  660 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 njs/njs_vm.c    |  431 +-----------------------------------
 njs/njs_vm.h    |  652 +-------------------------------------------------------
 6 files changed, 1091 insertions(+), 1072 deletions(-)

diffs (truncated from 2351 to 1000 lines):

diff -r e03f3e12589e -r 5c774a8c8332 auto/sources
--- a/auto/sources	Tue Jul 02 22:18:56 2019 -0400
+++ b/auto/sources	Sat Jul 06 10:27:14 2019 -0400
@@ -30,6 +30,7 @@ NXT_TEST_SRCS=" \
 
 NJS_LIB_SRCS=" \
    njs/njs.c \
+   njs/njs_value.c \
    njs/njs_vm.c \
    njs/njs_boolean.c \
    njs/njs_number.c \
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_core.h
--- a/njs/njs_core.h	Tue Jul 02 22:18:56 2019 -0400
+++ b/njs/njs_core.h	Sat Jul 06 10:27:14 2019 -0400
@@ -32,6 +32,7 @@
 #include <nxt_sprintf.h>
 
 #include <njs.h>
+#include <njs_value.h>
 #include <njs_vm.h>
 #include <njs_variable.h>
 #include <njs_lexer.h>
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_value.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_value.c	Sat Jul 06 10:27:14 2019 -0400
@@ -0,0 +1,418 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <njs_core.h>
+#include <string.h>
+
+
+const njs_value_t  njs_value_null =         njs_value(NJS_NULL, 0, 0.0);
+const njs_value_t  njs_value_undefined =    njs_value(NJS_UNDEFINED, 0, NAN);
+const njs_value_t  njs_value_false =        njs_value(NJS_BOOLEAN, 0, 0.0);
+const njs_value_t  njs_value_true =         njs_value(NJS_BOOLEAN, 1, 1.0);
+const njs_value_t  njs_value_zero =         njs_value(NJS_NUMBER, 0, 0.0);
+const njs_value_t  njs_value_nan =          njs_value(NJS_NUMBER, 0, NAN);
+const njs_value_t  njs_value_invalid =      njs_value(NJS_INVALID, 0, 0.0);
+
+const njs_value_t  njs_string_empty =       njs_string("");
+const njs_value_t  njs_string_comma =       njs_string(",");
+const njs_value_t  njs_string_null =        njs_string("null");
+const njs_value_t  njs_string_undefined =   njs_string("undefined");
+const njs_value_t  njs_string_boolean =     njs_string("boolean");
+const njs_value_t  njs_string_false =       njs_string("false");
+const njs_value_t  njs_string_true =        njs_string("true");
+const njs_value_t  njs_string_number =      njs_string("number");
+const njs_value_t  njs_string_minus_zero =  njs_string("-0");
+const njs_value_t  njs_string_minus_infinity =
+                                            njs_string("-Infinity");
+const njs_value_t  njs_string_plus_infinity =
+                                            njs_string("Infinity");
+const njs_value_t  njs_string_nan =         njs_string("NaN");
+const njs_value_t  njs_string_string =      njs_string("string");
+const njs_value_t  njs_string_object =      njs_string("object");
+const njs_value_t  njs_string_function =    njs_string("function");
+const njs_value_t  njs_string_memory_error = njs_string("MemoryError");
+
+
+void
+njs_value_retain(njs_value_t *value)
+{
+    njs_string_t  *string;
+
+    if (njs_is_string(value)) {
+
+        if (value->long_string.external != 0xff) {
+            string = value->long_string.data;
+
+            nxt_thread_log_debug("retain:%uxD \"%*s\"", string->retain,
+                                 value->long_string.size, string->start);
+
+            if (string->retain != 0xffff) {
+                string->retain++;
+            }
+        }
+    }
+}
+
+
+void
+njs_value_release(njs_vm_t *vm, njs_value_t *value)
+{
+    njs_string_t  *string;
+
+    if (njs_is_string(value)) {
+
+        if (value->long_string.external != 0xff) {
+            string = value->long_string.data;
+
+            nxt_thread_log_debug("release:%uxD \"%*s\"", string->retain,
+                                 value->long_string.size, string->start);
+
+            if (string->retain != 0xffff) {
+                string->retain--;
+
+#if 0
+                if (string->retain == 0) {
+                    if ((u_char *) string + sizeof(njs_string_t)
+                        != string->start)
+                    {
+                        nxt_memcache_pool_free(vm->mem_pool,
+                                               string->start);
+                    }
+
+                    nxt_memcache_pool_free(vm->mem_pool, string);
+                }
+#endif
+            }
+        }
+    }
+}
+
+
+nxt_bool_t
+njs_values_strict_equal(const njs_value_t *val1, const njs_value_t *val2)
+{
+    size_t        size, length1, length2;
+    const u_char  *start1, *start2;
+
+    if (val1->type != val2->type) {
+        return 0;
+    }
+
+    if (njs_is_numeric(val1)) {
+
+        if (njs_is_undefined(val1)) {
+            return 1;
+        }
+
+        /* Infinities are handled correctly by comparision. */
+        return (val1->data.u.number == val2->data.u.number);
+    }
+
+    if (njs_is_string(val1)) {
+        size = val1->short_string.size;
+
+        if (size != val2->short_string.size) {
+            return 0;
+        }
+
+        if (size != NJS_STRING_LONG) {
+            length1 = val1->short_string.length;
+            length2 = val2->short_string.length;
+
+            /*
+             * Using full memcmp() comparison if at least one string
+             * is a Byte string.
+             */
+            if (length1 != 0 && length2 != 0 && length1 != length2) {
+                return 0;
+            }
+
+            start1 = val1->short_string.start;
+            start2 = val2->short_string.start;
+
+        } else {
+            size = val1->long_string.size;
+
+            if (size != val2->long_string.size) {
+                return 0;
+            }
+
+            length1 = val1->long_string.data->length;
+            length2 = val2->long_string.data->length;
+
+            /*
+             * Using full memcmp() comparison if at least one string
+             * is a Byte string.
+             */
+            if (length1 != 0 && length2 != 0 && length1 != length2) {
+                return 0;
+            }
+
+            start1 = val1->long_string.data->start;
+            start2 = val2->long_string.data->start;
+        }
+
+        return (memcmp(start1, start2, size) == 0);
+    }
+
+    return (val1->data.u.object == val2->data.u.object);
+}
+
+
+/*
+ * A hint value is 0 for numbers and 1 for strings.  The value chooses
+ * method calls order specified by ECMAScript 5.1: "valueOf", "toString"
+ * for numbers and "toString", "valueOf" for strings.
+ */
+
+njs_ret_t
+njs_value_to_primitive(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint)
+{
+    njs_ret_t           ret;
+    njs_value_t         *retval;
+    njs_function_t      *function;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    static const uint32_t  hashes[] = {
+        NJS_VALUE_OF_HASH,
+        NJS_TO_STRING_HASH,
+    };
+
+    static const nxt_str_t  names[] = {
+        nxt_string("valueOf"),
+        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, value->data.u.object, &lhq);
+
+                    if (nxt_fast_path(prop != NULL)) {
+
+                        if (!njs_is_function(&prop->value)) {
+                            /* Try the second method. */
+                            continue;
+                        }
+
+                        function = prop->value.data.u.function;
+
+                        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);
+    }
+
+    vm->top_frame->trap_tries = 0;
+
+    return 1;
+}
+
+
+njs_array_t *
+njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
+    njs_object_enum_t kind, nxt_bool_t all)
+{
+    njs_object_value_t  obj_val;
+
+    if (njs_is_object(value)) {
+        return njs_object_enumerate(vm, value->data.u.object, kind, all);
+    }
+
+    if (value->type != NJS_STRING) {
+        return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
+    }
+
+    obj_val.object = vm->string_object;
+    obj_val.value = *value;
+
+    return njs_object_enumerate(vm, (njs_object_t *) &obj_val, kind, all);
+}
+
+
+njs_array_t *
+njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
+    njs_object_enum_t kind, nxt_bool_t all)
+{
+    njs_object_value_t  obj_val;
+
+    if (njs_is_object(value)) {
+        return njs_object_own_enumerate(vm, value->data.u.object, kind, all);
+    }
+
+    if (value->type != NJS_STRING) {
+        return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
+    }
+
+    obj_val.object = vm->string_object;
+    obj_val.value = *value;
+
+    return njs_object_own_enumerate(vm, (njs_object_t *) &obj_val, kind, all);
+}
+
+
+const char *
+njs_type_string(njs_value_type_t type)
+{
+    switch (type) {
+    case NJS_NULL:
+        return "null";
+
+    case NJS_UNDEFINED:
+        return "undefined";
+
+    case NJS_BOOLEAN:
+        return "boolean";
+
+    case NJS_NUMBER:
+        return "number";
+
+    case NJS_STRING:
+        return "string";
+
+    case NJS_EXTERNAL:
+        return "external";
+
+    case NJS_INVALID:
+        return "invalid";
+
+    case NJS_OBJECT:
+        return "object";
+
+    case NJS_ARRAY:
+        return "array";
+
+    case NJS_OBJECT_BOOLEAN:
+        return "object boolean";
+
+    case NJS_OBJECT_NUMBER:
+        return "object number";
+
+    case NJS_OBJECT_STRING:
+        return "object string";
+
+    case NJS_FUNCTION:
+        return "function";
+
+    case NJS_REGEXP:
+        return "regexp";
+
+    case NJS_DATE:
+        return "date";
+
+    case NJS_OBJECT_ERROR:
+        return "error";
+
+    case NJS_OBJECT_EVAL_ERROR:
+        return "eval error";
+
+    case NJS_OBJECT_INTERNAL_ERROR:
+        return "internal error";
+
+    case NJS_OBJECT_RANGE_ERROR:
+        return "range error";
+
+    case NJS_OBJECT_REF_ERROR:
+        return "reference error";
+
+    case NJS_OBJECT_SYNTAX_ERROR:
+        return "syntax error";
+
+    case NJS_OBJECT_TYPE_ERROR:
+        return "type error";
+
+    case NJS_OBJECT_URI_ERROR:
+        return "uri error";
+
+    default:
+        return NULL;
+    }
+}
+
+
+const char *
+njs_arg_type_string(uint8_t arg)
+{
+    switch (arg) {
+    case NJS_SKIP_ARG:
+        return "skip";
+
+    case NJS_NUMBER_ARG:
+        return "number";
+
+    case NJS_INTEGER_ARG:
+        return "integer";
+
+    case NJS_STRING_ARG:
+        return "string";
+
+    case NJS_OBJECT_ARG:
+        return "object";
+
+    case NJS_STRING_OBJECT_ARG:
+        return "string object";
+
+    case NJS_FUNCTION_ARG:
+        return "function";
+
+    case NJS_REGEXP_ARG:
+        return "regexp";
+
+    case NJS_DATE_ARG:
+        return "date";
+
+    default:
+        return "unknown";
+    }
+}
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_value.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_value.h	Sat Jul 06 10:27:14 2019 -0400
@@ -0,0 +1,660 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_VALUE_H_INCLUDED_
+#define _NJS_VALUE_H_INCLUDED_
+
+
+#include <nxt_trace.h>
+#include <nxt_queue.h>
+#include <nxt_regex.h>
+#include <nxt_random.h>
+#include <nxt_djb_hash.h>
+#include <nxt_mp.h>
+
+#include <math.h>
+
+
+/*
+ * The order of the enum is used in njs_vmcode_typeof()
+ * and njs_object_prototype_to_string().
+ */
+
+typedef enum {
+    NJS_NULL                  = 0x00,
+    NJS_UNDEFINED             = 0x01,
+
+    /* The order of the above type is used in njs_is_null_or_undefined(). */
+
+    NJS_BOOLEAN               = 0x02,
+    /*
+     * The order of the above type is used in
+     * njs_is_null_or_undefined_or_boolean().
+     */
+    NJS_NUMBER                = 0x03,
+    /*
+     * The order of the above type is used in njs_is_numeric().
+     * Booleans, null and void values can be used in mathematical operations:
+     *   a numeric value of the true value is one,
+     *   a numeric value of the null and false values is zero,
+     *   a numeric value of the void value is NaN.
+     */
+    NJS_STRING                = 0x04,
+
+    /* The order of the above type is used in njs_is_primitive(). */
+
+    NJS_DATA                  = 0x05,
+
+    /* The type is external code. */
+    NJS_EXTERNAL              = 0x06,
+
+    /*
+     * The invalid value type is used:
+     *   for uninitialized array members,
+     *   to detect non-declared explicitly or implicitly variables,
+     *   for native property getters.
+     */
+    NJS_INVALID               = 0x07,
+
+    /*
+     * The object types are >= NJS_OBJECT, this is used in njs_is_object().
+     * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be
+     * in the same order as NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING.  It is
+     * used in njs_primitive_prototype_index().  The order of object types
+     * is used in vm->prototypes and vm->constructors arrays.
+     */
+    NJS_OBJECT                = 0x10,
+    NJS_ARRAY                 = 0x11,
+    NJS_OBJECT_BOOLEAN        = 0x12,
+    NJS_OBJECT_NUMBER         = 0x13,
+    NJS_OBJECT_STRING         = 0x14,
+    NJS_FUNCTION              = 0x15,
+    NJS_REGEXP                = 0x16,
+    NJS_DATE                  = 0x17,
+    NJS_OBJECT_ERROR          = 0x18,
+    NJS_OBJECT_EVAL_ERROR     = 0x19,
+    NJS_OBJECT_INTERNAL_ERROR = 0x1a,
+    NJS_OBJECT_RANGE_ERROR    = 0x1b,
+    NJS_OBJECT_REF_ERROR      = 0x1c,
+    NJS_OBJECT_SYNTAX_ERROR   = 0x1d,
+    NJS_OBJECT_TYPE_ERROR     = 0x1e,
+    NJS_OBJECT_URI_ERROR      = 0x1f,
+    NJS_OBJECT_VALUE          = 0x20,
+#define NJS_TYPE_MAX         (NJS_OBJECT_VALUE + 1)
+} njs_value_type_t;
+
+
+/*
+ * njs_prop_handler_t operates as a property getter and/or setter.
+ * The handler receives NULL setval if it is invoked in GET context and
+ * non-null otherwise.
+ *
+ * njs_prop_handler_t is expected to return:
+ *   NXT_OK - handler executed successfully;
+ *   NXT_ERROR - some error, vm->retval contains appropriate exception;
+ *   NXT_DECLINED - handler was applied to inappropriate object.
+ */
+typedef njs_ret_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_value_t *value,
+    njs_value_t *setval, njs_value_t *retval);
+typedef njs_ret_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t retval);
+
+
+typedef struct njs_string_s           njs_string_t;
+typedef struct njs_object_s           njs_object_t;
+typedef struct njs_object_value_s     njs_object_value_t;
+typedef struct njs_function_lambda_s  njs_function_lambda_t;
+typedef struct njs_regexp_pattern_s   njs_regexp_pattern_t;
+typedef struct njs_array_s            njs_array_t;
+typedef struct njs_regexp_s           njs_regexp_t;
+typedef struct njs_date_s             njs_date_t;
+typedef struct njs_property_next_s    njs_property_next_t;
+typedef struct njs_object_init_s      njs_object_init_t;
+
+
+union njs_value_s {
+    /*
+     * The njs_value_t size is 16 bytes and must be aligned to 16 bytes
+     * to provide 4 bits to encode scope in njs_index_t.  This space is
+     * used to store short strings.  The maximum size of a short string
+     * is 14 (NJS_STRING_SHORT).  If the short_string.size field is 15
+     * (NJS_STRING_LONG) then the size is in the long_string.size field
+     * and the long_string.data field points to a long string.
+     *
+     * The number of the string types is limited to 2 types to minimize
+     * overhead of processing string fields.  It is also possible to add
+     * strings with size from 14 to 254 which size and length are stored in
+     * the string_size and string_length byte wide fields.  This will lessen
+     * the maximum size of short string to 13.
+     */
+    struct {
+        njs_value_type_t              type:8;  /* 6 bits */
+        /*
+         * The truth field is set during value assignment and then can be
+         * quickly tested by logical and conditional operations regardless
+         * of value type.  The truth field coincides with short_string.size
+         * and short_string.length so when string size and length are zero
+         * the string's value is false.
+         */
+        uint8_t                       truth;
+
+        uint16_t                      _spare1;
+        uint32_t                      _spare2;
+
+        union {
+            double                    number;
+            njs_object_t              *object;
+            njs_array_t               *array;
+            njs_object_value_t        *object_value;
+            njs_function_t            *function;
+            njs_function_lambda_t     *lambda;
+            njs_regexp_t              *regexp;
+            njs_date_t                *date;
+            njs_prop_handler_t        prop_handler;
+            njs_value_t               *value;
+            njs_property_next_t       *next;
+            void                      *data;
+        } u;
+    } data;
+
+    struct {
+        njs_value_type_t              type:8;  /* 6 bits */
+
+#define NJS_STRING_SHORT              14
+#define NJS_STRING_LONG               15
+
+        uint8_t                       size:4;
+        uint8_t                       length:4;
+
+        u_char                        start[NJS_STRING_SHORT];
+    } short_string;
+
+    struct {
+        njs_value_type_t              type:8;  /* 6 bits */
+        uint8_t                       truth;
+
+        /* 0xff if data is external string. */
+        uint8_t                       external;
+        uint8_t                       _spare;
+
+        uint32_t                      size;
+        njs_string_t                  *data;
+    } long_string;
+
+    struct {
+        njs_value_type_t              type:8;  /* 6 bits */
+        uint8_t                       truth;
+
+        uint16_t                      _spare;
+
+        uint32_t                      index;
+        const njs_extern_t            *proto;
+    } external;
+
+    njs_value_type_t                  type:8;  /* 6 bits */
+};
+
+
+struct njs_object_s {
+    /* A private hash of njs_object_prop_t. */
+    nxt_lvlhsh_t                      hash;
+
+    /* A shared hash of njs_object_prop_t. */
+    nxt_lvlhsh_t                      shared_hash;
+
+    /* An object __proto__. */
+    njs_object_t                      *__proto__;
+
+    /* The type is used in constructor prototypes. */
+    njs_value_type_t                  type:8;
+    uint8_t                           shared;     /* 1 bit */
+    uint8_t                           extensible; /* 1 bit */
+};
+
+
+struct njs_object_value_s {
+    njs_object_t                      object;
+    /* The value can be unaligned since it never used in nJSVM operations. */
+    njs_value_t                       value;
+};
+
+
+struct njs_array_s {
+    njs_object_t                      object;
+    uint32_t                          size;
+    uint32_t                          length;
+    njs_value_t                       *start;
+    njs_value_t                       *data;
+};
+
+
+typedef struct {
+    union {
+        uint32_t                      count;
+        njs_value_t                   values;
+    } u;
+
+    njs_value_t                       values[1];
+} njs_closure_t;
+
+
+#define NJS_ARGS_TYPES_MAX            5
+
+struct njs_function_s {
+    njs_object_t                      object;
+
+    uint8_t                           args_types[NJS_ARGS_TYPES_MAX];
+    uint8_t                           args_offset;
+    uint8_t                           continuation_size;
+
+    /* Function is a closure. */
+    uint8_t                           closure:1;
+
+    uint8_t                           native:1;
+    uint8_t                           ctor:1;
+
+    union {
+        njs_function_lambda_t         *lambda;
+        njs_function_native_t         native;
+    } u;
+
+    njs_value_t                       *bound;
+#if (NXT_SUNC)
+    njs_closure_t                     *closures[1];
+#else
+    njs_closure_t                     *closures[];
+#endif
+};
+
+
+struct njs_regexp_s {
+    njs_object_t                      object;
+    uint32_t                          last_index;
+    njs_regexp_pattern_t              *pattern;
+    /*
+     * This string value can be unaligned since
+     * it never used in nJSVM operations.
+     */
+    njs_value_t                       string;
+};
+
+
+struct njs_date_s {
+    njs_object_t                      object;
+    double                            time;
+};
+
+
+typedef union {
+    njs_object_t                      object;
+    njs_object_value_t                object_value;
+    njs_array_t                       array;
+    njs_function_t                    function;
+    njs_regexp_t                      regexp;
+    njs_date_t                        date;
+} njs_object_prototype_t;
+
+
+typedef enum {
+    NJS_ENUM_KEYS,
+    NJS_ENUM_VALUES,
+    NJS_ENUM_BOTH,
+} njs_object_enum_t;
+
+
+#define njs_value(_type, _truth, _number) {                                   \
+    .data = {                                                                 \
+        .type = _type,                                                        \
+        .truth = _truth,                                                      \
+        .u.number = _number,                                                  \
+    }                                                                         \
+}
+
+
+#define njs_string(s) {                                                       \
+    .short_string = {                                                         \
+        .type = NJS_STRING,                                                   \
+        .size = nxt_length(s),                                                \
+        .length = nxt_length(s),                                              \
+        .start = s,                                                           \
+    }                                                                         \
+}
+
+
+/* NJS_STRING_LONG is set for both big and little endian platforms. */
+
+#define njs_long_string(s) {                                                  \
+    .long_string = {                                                          \
+        .type = NJS_STRING,                                                   \
+        .truth = (NJS_STRING_LONG << 4) | NJS_STRING_LONG,                    \
+        .size = nxt_length(s),                                                \
+        .data = & (njs_string_t) {                                            \
+            .start = (u_char *) s,                                            \
+            .length = nxt_length(s),                                          \
+        }                                                                     \
+    }                                                                         \
+}
+
+
+#define njs_native_function(_function, _size, ...) {                          \
+    .data = {                                                                 \
+        .type = NJS_FUNCTION,                                                 \
+        .truth = 1,                                                           \
+        .u.function = & (njs_function_t) {                                    \
+            .native = 1,                                                      \
+            .continuation_size = _size,                                       \
+            .args_types = { __VA_ARGS__ },                                    \
+            .args_offset = 1,                                                 \
+            .u.native = _function,                                            \
+            .object = { .type = NJS_FUNCTION,                                 \
+                        .shared = 1,                                          \
+                        .extensible = 1 },                                    \
+        }                                                                     \
+    }                                                                         \
+}
+
+
+#define njs_prop_handler(_handler) {                                          \
+    .data = {                                                                 \
+        .type = NJS_INVALID,                                                  \
+        .truth = 1,                                                           \
+        .u = { .prop_handler = _handler }                                     \
+    }                                                                         \
+}
+
+
+#define njs_is_null(value)                                                    \
+    ((value)->type == NJS_NULL)
+
+
+#define njs_is_undefined(value)                                               \
+    ((value)->type == NJS_UNDEFINED)
+
+
+#define njs_is_null_or_undefined(value)                                       \
+    ((value)->type <= NJS_UNDEFINED)
+
+
+#define njs_is_boolean(value)                                                 \
+    ((value)->type == NJS_BOOLEAN)
+
+
+#define njs_is_null_or_undefined_or_boolean(value)                            \
+    ((value)->type <= NJS_BOOLEAN)
+
+
+#define njs_is_true(value)                                                    \
+    ((value)->data.truth != 0)
+
+
+#define njs_is_number(value)                                                  \
+    ((value)->type == NJS_NUMBER)
+
+
+/* Testing for NaN first generates a better code at least on i386/amd64. */
+
+#define njs_is_number_true(num)                                               \
+    (!isnan(num) && num != 0)
+
+
+#define njs_is_numeric(value)                                                 \
+    ((value)->type <= NJS_NUMBER)
+
+
+#define njs_is_string(value)                                                  \
+    ((value)->type == NJS_STRING)
+
+#define njs_is_error(value)                                                   \
+    ((value)->type >= NJS_OBJECT_ERROR                                        \
+     && (value)->type <= NJS_OBJECT_URI_ERROR)
+
+
+/*
+ * The truth field coincides with short_string.size and short_string.length
+ * so when string size and length are zero the string's value is false and
+ * otherwise is true.
+ */
+#define njs_string_truth(value, size)
+
+
+#define njs_string_get(value, str)                                            \
+    do {                                                                      \
+        if ((value)->short_string.size != NJS_STRING_LONG) {                  \
+            (str)->length = (value)->short_string.size;                       \
+            (str)->start = (u_char *) (value)->short_string.start;            \
+                                                                              \
+        } else {                                                              \
+            (str)->length = (value)->long_string.size;                        \
+            (str)->start = (u_char *) (value)->long_string.data->start;       \
+        }                                                                     \
+    } while (0)
+
+
+#define njs_string_short_start(value)                                         \
+    (value)->short_string.start
+
+
+#define njs_string_short_set(value, _size, _length)                           \
+    do {                                                                      \
+        (value)->type = NJS_STRING;                                           \
+        njs_string_truth(value, _size);                                       \
+        (value)->short_string.size = _size;                                   \
+        (value)->short_string.length = _length;                               \
+    } while (0)
+
+
+#define njs_string_length_set(value, _length)                                 \
+    do {                                                                      \
+        if ((value)->short_string.size != NJS_STRING_LONG) {                  \
+            (value)->short_string.length = length;                            \
+                                                                              \
+        } else {                                                              \
+            (value)->long_string.data->length = length;                       \
+        }                                                                     \
+    } while (0)
+
+#define njs_is_primitive(value)                                               \
+    ((value)->type <= NJS_STRING)
+
+
+#define njs_is_data(value)                                                    \
+    ((value)->type == NJS_DATA)
+
+
+#define njs_is_object(value)                                                  \
+    ((value)->type >= NJS_OBJECT)
+
+
+#define njs_is_object_value(value)                                            \
+    ((value)->type == NJS_OBJECT_VALUE)
+
+
+#define njs_object_value_type(type)                                           \
+    (type + NJS_OBJECT)
+
+
+#define njs_is_array(value)                                                   \
+    ((value)->type == NJS_ARRAY)
+
+
+#define njs_is_function(value)                                                \
+    ((value)->type == NJS_FUNCTION)
+
+
+#define njs_is_regexp(value)                                                  \
+    ((value)->type == NJS_REGEXP)
+
+
+#define njs_is_date(value)                                                    \
+    ((value)->type == NJS_DATE)
+
+
+#define njs_is_external(value)                                                \
+    ((value)->type == NJS_EXTERNAL)
+
+
+#define njs_is_valid(value)                                                   \
+    ((value)->type != NJS_INVALID)
+
+
+#define njs_bool(value)                                                       \
+    ((value)->data.truth)
+
+
+#define njs_number(value)                                                     \
+    ((value)->data.u.number)
+
+
+#define njs_data(value)                                                       \
+    ((value)->data.u.data)
+
+
+#define njs_function(value)                                                   \
+    ((value)->data.u.function)
+
+
+#define njs_object(value)                                                     \
+    ((value)->data.u.object)
+
+
+#define njs_object_hash(value)                                                \
+    (&(value)->data.u.object->hash)
+
+
+#define njs_array(value)                                                      \
+    ((value)->data.u.array)
+
+
+#define njs_array_len(value)                                                  \
+    ((value)->data.u.array->length)
+
+
+#define njs_array_start(value)                                                \
+    ((value)->data.u.array->start)
+
+
+#define njs_set_undefined(value)                                              \
+    *(value) = njs_value_undefined
+
+
+#define njs_set_boolean(value, yn)                                            \
+    *(value) = yn ? njs_value_true : njs_value_false
+
+
+#define njs_set_true(value)                                                   \
+    *(value) = njs_value_true
+
+
+#define njs_set_false(value)                                                  \
+    *(value) = njs_value_false


More information about the nginx-devel mailing list