1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #ifndef _NJS_VALUE_H_INCLUDED_
8 #define _NJS_VALUE_H_INCLUDED_
9 
10 
11 /*
12  * The order of the enum is used in njs_vmcode_typeof()
13  * and njs_object_prototype_to_string().
14  */
15 
16 typedef enum {
17     NJS_NULL,
18     NJS_UNDEFINED,
19 
20     /* The order of the above type is used in njs_is_null_or_undefined(). */
21 
22     NJS_BOOLEAN,
23     /*
24      * The order of the above type is used in
25      * njs_is_null_or_undefined_or_boolean().
26      */
27     NJS_NUMBER,
28     /*
29      * The order of the above type is used in njs_is_numeric().
30      * Booleans, null and void values can be used in mathematical operations:
31      *   a numeric value of the true value is one,
32      *   a numeric value of the null and false values is zero,
33      *   a numeric value of the void value is NaN.
34      */
35     NJS_SYMBOL,
36 
37     NJS_STRING,
38 
39     /* The order of the above type is used in njs_is_primitive(). */
40 
41     NJS_DATA,
42 
43     /*
44      * The invalid value type is used:
45      *   for uninitialized array members,
46      *   to detect non-declared explicitly or implicitly variables,
47      *   for native property getters.
48      */
49     NJS_INVALID,
50 
51     NJS_OBJECT                = 0x10,
52     NJS_ARRAY,
53 #define NJS_OBJECT_SPECIAL_MIN  (NJS_FUNCTION)
54     NJS_FUNCTION,
55     NJS_REGEXP,
56     NJS_DATE,
57     NJS_TYPED_ARRAY,
58 #define NJS_OBJECT_SPECIAL_MAX  (NJS_TYPED_ARRAY + 1)
59     NJS_PROMISE,
60     NJS_OBJECT_VALUE,
61     NJS_ARRAY_BUFFER,
62     NJS_DATA_VIEW,
63     NJS_VALUE_TYPE_MAX
64 } njs_value_type_t;
65 
66 
67 typedef enum {
68     NJS_DATA_TAG_ANY = 0,
69     NJS_DATA_TAG_EXTERNAL,
70     NJS_DATA_TAG_TEXT_ENCODER,
71     NJS_DATA_TAG_TEXT_DECODER,
72     NJS_DATA_TAG_ARRAY_ITERATOR,
73     NJS_DATA_TAG_FS_STAT,
74     NJS_DATA_TAG_MAX
75 } njs_data_tag_t;
76 
77 
78 typedef struct njs_string_s           njs_string_t;
79 typedef struct njs_object_s           njs_object_t;
80 typedef struct njs_object_value_s     njs_object_value_t;
81 typedef struct njs_function_lambda_s  njs_function_lambda_t;
82 typedef struct njs_regexp_pattern_s   njs_regexp_pattern_t;
83 typedef struct njs_array_s            njs_array_t;
84 typedef struct njs_array_buffer_s     njs_array_buffer_t;
85 typedef struct njs_typed_array_s      njs_typed_array_t;
86 typedef struct njs_typed_array_s      njs_data_view_t;
87 typedef struct njs_regexp_s           njs_regexp_t;
88 typedef struct njs_date_s             njs_date_t;
89 typedef struct njs_object_value_s     njs_promise_t;
90 typedef struct njs_property_next_s    njs_property_next_t;
91 typedef struct njs_object_init_s      njs_object_init_t;
92 
93 
94 union njs_value_s {
95     /*
96      * The njs_value_t size is 16 bytes and must be aligned to 16 bytes
97      * to provide 4 bits to encode scope in njs_index_t.  This space is
98      * used to store short strings.  The maximum size of a short string
99      * is 14 (NJS_STRING_SHORT).  If the short_string.size field is 15
100      * (NJS_STRING_LONG) then the size is in the long_string.size field
101      * and the long_string.data field points to a long string.
102      *
103      * The number of the string types is limited to 2 types to minimize
104      * overhead of processing string fields.  It is also possible to add
105      * strings with size from 14 to 254 which size and length are stored in
106      * the string_size and string_length byte wide fields.  This will lessen
107      * the maximum size of short string to 13.
108      */
109     struct {
110         njs_value_type_t              type:8;  /* 6 bits */
111         /*
112          * The truth field is set during value assignment and then can be
113          * quickly tested by logical and conditional operations regardless
114          * of value type.  The truth field coincides with short_string.size
115          * and short_string.length so when string size and length are zero
116          * the string's value is false.
117          */
118         uint8_t                       truth;
119 
120         uint16_t                      magic16;
121         uint32_t                      magic32;
122 
123         union {
124             double                    number;
125             njs_object_t              *object;
126             njs_array_t               *array;
127             njs_array_buffer_t        *array_buffer;
128             njs_typed_array_t         *typed_array;
129             njs_data_view_t           *data_view;
130             njs_object_value_t        *object_value;
131             njs_function_t            *function;
132             njs_function_lambda_t     *lambda;
133             njs_regexp_t              *regexp;
134             njs_date_t                *date;
135             njs_promise_t             *promise;
136             njs_prop_handler_t        prop_handler;
137             njs_value_t               *value;
138             njs_property_next_t       *next;
139             void                      *data;
140         } u;
141     } data;
142 
143     struct {
144         njs_value_type_t              type:8;  /* 6 bits */
145 
146 #define NJS_STRING_SHORT              14
147 #define NJS_STRING_LONG               15
148 
149         uint8_t                       size:4;
150         uint8_t                       length:4;
151 
152         u_char                        start[NJS_STRING_SHORT];
153     } short_string;
154 
155     struct {
156         njs_value_type_t              type:8;  /* 6 bits */
157         uint8_t                       truth;
158 
159         /* 0xff if data is external string. */
160         uint8_t                       external;
161         uint8_t                       _spare;
162 
163         uint32_t                      size;
164         njs_string_t                  *data;
165     } long_string;
166 
167     njs_value_type_t                  type:8;  /* 6 bits */
168 };
169 
170 
171 typedef struct {
172     /* Get, also Set if writable, also Delete if configurable. */
173     njs_prop_handler_t  prop_handler;
174     uint32_t            magic32;
175     unsigned            writable:1;
176     unsigned            configurable:1;
177     unsigned            enumerable:1;
178 
179     njs_exotic_keys_t   keys;
180 
181     /* A shared hash of njs_object_prop_t for externals. */
182     njs_lvlhsh_t        external_shared_hash;
183 } njs_exotic_slots_t;
184 
185 
186 struct njs_object_s {
187     /* A private hash of njs_object_prop_t. */
188     njs_lvlhsh_t                      hash;
189 
190     /* A shared hash of njs_object_prop_t. */
191     njs_lvlhsh_t                      shared_hash;
192 
193     njs_object_t                      *__proto__;
194     njs_exotic_slots_t                *slots;
195 
196     /* The type is used in constructor prototypes. */
197     njs_value_type_t                  type:8;
198     uint8_t                           shared;     /* 1 bit */
199 
200     uint8_t                           extensible:1;
201     uint8_t                           error_data:1;
202     uint8_t                           fast_array:1;
203 };
204 
205 
206 struct njs_object_value_s {
207     njs_object_t                      object;
208     /* The value can be unaligned since it never used in nJSVM operations. */
209     njs_value_t                       value;
210 };
211 
212 
213 struct njs_array_s {
214     njs_object_t                      object;
215     uint32_t                          size;
216     uint32_t                          length;
217     njs_value_t                       *start;
218     njs_value_t                       *data;
219 };
220 
221 
222 struct njs_array_buffer_s {
223     njs_object_t                      object;
224     size_t                            size;
225     union {
226         uint8_t                       *u8;
227         uint16_t                      *u16;
228         uint32_t                      *u32;
229         uint64_t                      *u64;
230         int8_t                        *i8;
231         int16_t                       *i16;
232         int32_t                       *i32;
233         int64_t                       *i64;
234         float                         *f32;
235         double                        *f64;
236 
237         void                          *data;
238     } u;
239 };
240 
241 
242 struct njs_typed_array_s {
243     njs_object_t                      object;
244     njs_array_buffer_t                *buffer;
245     size_t                            offset; // byte_offset / element_size
246     size_t                            byte_length;
247     uint8_t                           type;
248 };
249 
250 
251 struct njs_function_s {
252     njs_object_t                      object;
253 
254     uint8_t                           args_offset;
255 
256     uint8_t                           args_count:4;
257 
258     uint8_t                           closure_copied:1;
259     uint8_t                           native:1;
260     uint8_t                           ctor:1;
261     uint8_t                           global_this:1;
262     uint8_t                           global:1;
263 
264     uint8_t                           magic8;
265 
266     union {
267         njs_function_lambda_t         *lambda;
268         njs_function_native_t         native;
269         njs_function_t                *bound_target;
270     } u;
271 
272     void                              *context;
273     void                              *await;
274 
275     njs_value_t                       *bound;
276 };
277 
278 
279 struct njs_regexp_s {
280     njs_object_t                      object;
281     njs_value_t                       last_index;
282     njs_regexp_pattern_t              *pattern;
283     /*
284      * This string value can be unaligned since
285      * it never used in nJSVM operations.
286      */
287     njs_value_t                       string;
288 };
289 
290 
291 struct njs_date_s {
292     njs_object_t                      object;
293     double                            time;
294 };
295 
296 
297 typedef union {
298     njs_object_t                      object;
299     njs_object_value_t                object_value;
300     njs_array_t                       array;
301     njs_function_t                    function;
302     njs_regexp_t                      regexp;
303     njs_date_t                        date;
304     njs_promise_t                     promise;
305 } njs_object_prototype_t;
306 
307 
308 typedef struct {
309     njs_function_t            constructor;
310     const njs_object_init_t   *constructor_props;
311     const njs_object_init_t   *prototype_props;
312     njs_object_prototype_t    prototype_value;
313 } njs_object_type_init_t;
314 
315 
316 typedef enum {
317     NJS_ENUM_KEYS,
318     NJS_ENUM_VALUES,
319     NJS_ENUM_BOTH,
320 } njs_object_enum_t;
321 
322 
323 typedef enum {
324     NJS_ENUM_STRING = 1,
325     NJS_ENUM_SYMBOL = 2,
326 } njs_object_enum_type_t;
327 
328 
329 typedef enum {
330     NJS_PROPERTY = 0,
331     NJS_PROPERTY_REF,
332     NJS_PROPERTY_TYPED_ARRAY_REF,
333     NJS_PROPERTY_HANDLER,
334     NJS_WHITEOUT,
335 } njs_object_prop_type_t;
336 
337 
338 /*
339  * Attributes are generally used as Boolean values.
340  * The UNSET value is can be seen:
341  * for newly created property descriptors in njs_define_property(),
342  * for writable attribute of accessor descriptors (desc->writable
343  * cannot be used as a boolean value).
344  */
345 typedef enum {
346     NJS_ATTRIBUTE_FALSE = 0,
347     NJS_ATTRIBUTE_TRUE = 1,
348     NJS_ATTRIBUTE_UNSET,
349 } njs_object_attribute_t;
350 
351 
352 struct njs_object_prop_s {
353     /* Must be aligned to njs_value_t. */
354     njs_value_t                 value;
355     njs_value_t                 name;
356     njs_value_t                 getter;
357     njs_value_t                 setter;
358 
359     /* TODO: get rid of types */
360     njs_object_prop_type_t      type:8;          /* 3 bits */
361 
362     njs_object_attribute_t      writable:8;      /* 2 bits */
363     njs_object_attribute_t      enumerable:8;    /* 2 bits */
364     njs_object_attribute_t      configurable:8;  /* 2 bits */
365 };
366 
367 
368 typedef struct {
369     njs_lvlhsh_query_t          lhq;
370 
371     /* scratch is used to get the value of an NJS_PROPERTY_HANDLER property. */
372     njs_object_prop_t           scratch;
373 
374     njs_value_t                 key;
375     njs_object_t                *prototype;
376     njs_object_prop_t           *own_whiteout;
377     uint8_t                     query;
378     uint8_t                     shared;
379     uint8_t                     own;
380 } njs_property_query_t;
381 
382 
383 #define njs_value(_type, _truth, _number) {                                   \
384     .data = {                                                                 \
385         .type = _type,                                                        \
386         .truth = _truth,                                                      \
387         .u.number = _number,                                                  \
388     }                                                                         \
389 }
390 
391 
392 #define njs_wellknown_symbol(key) {                                           \
393     .data = {                                                                 \
394         .type = NJS_SYMBOL,                                                   \
395         .truth = 1,                                                           \
396         .magic32 = key,                                                       \
397         .u = { .value = NULL }                                                \
398     }                                                                         \
399 }
400 
401 
402 #define njs_string(s) {                                                       \
403     .short_string = {                                                         \
404         .type = NJS_STRING,                                                   \
405         .size = njs_length(s),                                                \
406         .length = njs_length(s),                                              \
407         .start = s,                                                           \
408     }                                                                         \
409 }
410 
411 
412 /* NJS_STRING_LONG is set for both big and little endian platforms. */
413 
414 #define njs_long_string(s) {                                                  \
415     .long_string = {                                                          \
416         .type = NJS_STRING,                                                   \
417         .truth = (NJS_STRING_LONG << 4) | NJS_STRING_LONG,                    \
418         .size = njs_length(s),                                                \
419         .data = & (njs_string_t) {                                            \
420             .start = (u_char *) s,                                            \
421             .length = njs_length(s),                                          \
422         }                                                                     \
423     }                                                                         \
424 }
425 
426 
427 #define _njs_function(_function, _args_count, _ctor, _magic) {                \
428     .native = 1,                                                              \
429     .magic8 = _magic,                                                         \
430     .args_count = _args_count,                                                \
431     .ctor = _ctor,                                                            \
432     .args_offset = 1,                                                         \
433     .u.native = _function,                                                    \
434     .object = { .type = NJS_FUNCTION,                                         \
435                 .shared = 1,                                                  \
436                 .extensible = 1 },                                            \
437 }
438 
439 
440 #define _njs_native_function(_func, _args, _ctor, _magic) {                   \
441     .data = {                                                                 \
442         .type = NJS_FUNCTION,                                                 \
443         .truth = 1,                                                           \
444         .u.function = & (njs_function_t) _njs_function(_func, _args,          \
445                                                        _ctor, _magic)         \
446     }                                                                         \
447 }
448 
449 
450 #define njs_native_function(_function, _args_count)                           \
451     _njs_native_function(_function, _args_count, 0, 0)
452 
453 
454 #define njs_native_function2(_function, _args_count, _magic)                  \
455     _njs_native_function(_function, _args_count, 0, _magic)
456 
457 
458 #define njs_native_ctor(_function, _args_count, _magic)                       \
459     _njs_function(_function, _args_count, 1, _magic)
460 
461 
462 #define njs_prop_handler(_handler) {                                          \
463     .data = {                                                                 \
464         .type = NJS_INVALID,                                                  \
465         .truth = 1,                                                           \
466         .u = { .prop_handler = _handler }                                     \
467     }                                                                         \
468 }
469 
470 
471 #define njs_prop_handler2(_handler, _magic16, _magic32) {                     \
472     .data = {                                                                 \
473         .type = NJS_INVALID,                                                  \
474         .truth = 1,                                                           \
475         .magic16 = _magic16,                                                  \
476         .magic32 = _magic32,                                                  \
477         .u = { .prop_handler = _handler }                                     \
478     }                                                                         \
479 }
480 
481 
482 #define njs_is_null(value)                                                    \
483     ((value)->type == NJS_NULL)
484 
485 
486 #define njs_is_undefined(value)                                               \
487     ((value)->type == NJS_UNDEFINED)
488 
489 
490 #define njs_is_defined(value)                                                 \
491     ((value)->type != NJS_UNDEFINED)
492 
493 
494 #define njs_is_null_or_undefined(value)                                       \
495     ((value)->type <= NJS_UNDEFINED)
496 
497 
498 #define njs_is_boolean(value)                                                 \
499     ((value)->type == NJS_BOOLEAN)
500 
501 
502 #define njs_is_null_or_undefined_or_boolean(value)                            \
503     ((value)->type <= NJS_BOOLEAN)
504 
505 
506 #define njs_is_true(value)                                                    \
507     ((value)->data.truth != 0)
508 
509 
510 #define njs_is_number(value)                                                  \
511     ((value)->type == NJS_NUMBER)
512 
513 
514 /* Testing for NaN first generates a better code at least on i386/amd64. */
515 
516 #define njs_is_number_true(num)                                               \
517     (!isnan(num) && num != 0)
518 
519 
520 #define njs_is_numeric(value)                                                 \
521     ((value)->type <= NJS_NUMBER)
522 
523 
524 #define njs_is_symbol(value)                                                  \
525     ((value)->type == NJS_SYMBOL)
526 
527 
528 #define njs_is_string(value)                                                  \
529     ((value)->type == NJS_STRING)
530 
531 
532 #define njs_is_key(value)                                                     \
533     (njs_is_string(value) || njs_is_symbol(value))
534 
535 
536 /*
537  * The truth field coincides with short_string.size and short_string.length
538  * so when string size and length are zero the string's value is false and
539  * otherwise is true.
540  */
541 #define njs_string_truth(value, size)
542 
543 
544 #define njs_string_get(value, str)                                            \
545     do {                                                                      \
546         if ((value)->short_string.size != NJS_STRING_LONG) {                  \
547             (str)->length = (value)->short_string.size;                       \
548             (str)->start = (u_char *) (value)->short_string.start;            \
549                                                                               \
550         } else {                                                              \
551             (str)->length = (value)->long_string.size;                        \
552             (str)->start = (u_char *) (value)->long_string.data->start;       \
553         }                                                                     \
554     } while (0)
555 
556 
557 #define njs_string_short_start(value)                                         \
558     (value)->short_string.start
559 
560 
561 #define njs_string_short_set(value, _size, _length)                           \
562     do {                                                                      \
563         (value)->type = NJS_STRING;                                           \
564         njs_string_truth(value, _size);                                       \
565         (value)->short_string.size = _size;                                   \
566         (value)->short_string.length = _length;                               \
567     } while (0)
568 
569 
570 #define njs_string_length_set(value, _length)                                 \
571     do {                                                                      \
572         if ((value)->short_string.size != NJS_STRING_LONG) {                  \
573             (value)->short_string.length = length;                            \
574                                                                               \
575         } else {                                                              \
576             (value)->long_string.data->length = length;                       \
577         }                                                                     \
578     } while (0)
579 
580 #define njs_is_primitive(value)                                               \
581     ((value)->type <= NJS_STRING)
582 
583 
584 #define njs_make_tag(proto_id)                                                \
585     (((njs_uint_t) proto_id << 8) | NJS_DATA_TAG_EXTERNAL)
586 
587 
588 #define njs_is_data(value, tag)                                               \
589     ((value)->type == NJS_DATA                                                \
590      && ((tag) == njs_make_tag(NJS_PROTO_ID_ANY)                              \
591          || value->data.magic32 == (tag)))
592 
593 
594 #define njs_is_object(value)                                                  \
595     ((value)->type >= NJS_OBJECT)
596 
597 
598 #define njs_has_prototype(vm, value, proto)                                   \
599     (((njs_object_prototype_t *)                                              \
600         njs_object(value)->__proto__ - (vm)->prototypes) == proto)
601 
602 
603 #define njs_is_object_value(value)                                            \
604     ((value)->type == NJS_OBJECT_VALUE)
605 
606 
607 #define njs_is_object_boolean(_value)                                         \
608     (((_value)->type == NJS_OBJECT_VALUE)                                     \
609      && njs_is_boolean(njs_object_value(_value)))
610 
611 
612 #define njs_is_object_number(_value)                                          \
613     (((_value)->type == NJS_OBJECT_VALUE)                                     \
614      && njs_is_number(njs_object_value(_value)))
615 
616 
617 #define njs_is_object_symbol(_value)                                          \
618     (((_value)->type == NJS_OBJECT_VALUE)                                     \
619      && njs_is_symbol(njs_object_value(_value)))
620 
621 
622 #define njs_is_object_string(_value)                                          \
623     (((_value)->type == NJS_OBJECT_VALUE)                                     \
624      && njs_is_string(njs_object_value(_value)))
625 
626 
627 #define njs_is_object_primitive(_value)                                       \
628     (((_value)->type == NJS_OBJECT_VALUE)                                     \
629      && njs_is_primitive(njs_object_value(_value)))
630 
631 
632 #define njs_is_object_data(_value, tag)                                       \
633     (((_value)->type == NJS_OBJECT_VALUE)                                     \
634      && njs_is_data(njs_object_value(_value), tag))
635 
636 
637 #define njs_is_array(value)                                                   \
638     ((value)->type == NJS_ARRAY)
639 
640 
641 #define njs_is_fast_array(value)                                              \
642     (njs_is_array(value) && njs_array(value)->object.fast_array)
643 
644 
645 #define njs_is_array_buffer(value)                                            \
646     ((value)->type == NJS_ARRAY_BUFFER)
647 
648 
649 #define njs_is_typed_array(value)                                             \
650     ((value)->type == NJS_TYPED_ARRAY)
651 
652 
653 #define njs_is_detached_buffer(buffer)                                        \
654     ((buffer)->u.data == NULL)
655 
656 
657 #define njs_is_data_view(value)                                               \
658     ((value)->type == NJS_DATA_VIEW)
659 
660 
661 #define njs_is_typed_array_uint8(value)                                       \
662     (njs_is_typed_array(value)                                                \
663      && njs_typed_array(value)->type == NJS_OBJ_TYPE_UINT8_ARRAY)
664 
665 
666 #define njs_is_function(value)                                                \
667     ((value)->type == NJS_FUNCTION)
668 
669 
670 #define njs_is_function_or_undefined(value)                                   \
671     ((value)->type == NJS_FUNCTION || (value)->type == NJS_UNDEFINED)
672 
673 
674 #define njs_is_constructor(value)                                             \
675     (njs_is_function(value) && njs_function(value)->ctor)
676 
677 
678 #define njs_is_regexp(value)                                                  \
679     ((value)->type == NJS_REGEXP)
680 
681 
682 #define njs_is_date(value)                                                    \
683     ((value)->type == NJS_DATE)
684 
685 
686 #define njs_is_promise(value)                                                 \
687     ((value)->type == NJS_PROMISE)
688 
689 
690 #define njs_is_error(value)                                                   \
691     ((value)->type == NJS_OBJECT && njs_object(value)->error_data)
692 
693 
694 #define njs_is_valid(value)                                                   \
695     ((value)->type != NJS_INVALID)
696 
697 
698 #define njs_bool(value)                                                       \
699     ((value)->data.truth)
700 
701 
702 #define njs_number(value)                                                     \
703     ((value)->data.u.number)
704 
705 
706 #define njs_data(value)                                                       \
707     ((value)->data.u.data)
708 
709 
710 #define njs_function(value)                                                   \
711     ((value)->data.u.function)
712 
713 
714 #define njs_function_lambda(value)                                            \
715     ((value)->data.u.function->u.lambda)
716 
717 
718 #define njs_object(value)                                                     \
719     ((value)->data.u.object)
720 
721 
722 #define njs_object_hash(value)                                                \
723     (&(value)->data.u.object->hash)
724 
725 
726 #define njs_object_slots(value)                                               \
727     ((value)->data.u.object->slots)
728 
729 
730 #define njs_array(value)                                                      \
731     ((value)->data.u.array)
732 
733 
734 #define njs_array_len(value)                                                  \
735     ((value)->data.u.array->length)
736 
737 
738 #define njs_array_buffer(value)                                               \
739     ((value)->data.u.array_buffer)
740 
741 
742 #define njs_data_view(value)                                                  \
743     ((value)->data.u.data_view)
744 
745 
746 #define njs_typed_array(value)                                                \
747     ((value)->data.u.typed_array)
748 
749 
750 #define njs_typed_array_buffer(value)                                         \
751     ((value)->buffer)
752 
753 
754 #define njs_array_start(value)                                                \
755     ((value)->data.u.array->start)
756 
757 
758 #define njs_date(value)                                                       \
759     ((value)->data.u.date)
760 
761 
762 #define njs_promise(value)                                                    \
763     ((value)->data.u.promise)
764 
765 
766 #define njs_regexp(value)                                                     \
767     ((value)->data.u.regexp)
768 
769 
770 #define njs_regexp_pattern(value)                                             \
771     ((value)->data.u.regexp->pattern)
772 
773 
774 #define njs_object_value(_value)                                              \
775     (&(_value)->data.u.object_value->value)
776 
777 
778 #define njs_object_data(_value)                                               \
779     njs_data(njs_object_value(_value))
780 
781 
782 #define njs_set_undefined(value)                                              \
783     *(value) = njs_value_undefined
784 
785 
786 #define njs_set_null(value)                                                   \
787     *(value) = njs_value_null
788 
789 
790 #define njs_set_true(value)                                                   \
791     *(value) = njs_value_true
792 
793 
794 #define njs_set_false(value)                                                  \
795     *(value) = njs_value_false
796 
797 
798 #define njs_symbol_key(value)                                                 \
799     ((value)->data.magic32)
800 
801 
802 #define njs_symbol_eq(value1, value2)                                         \
803     (njs_symbol_key(value1) == njs_symbol_key(value2))
804 
805 
806 extern const njs_value_t  njs_value_null;
807 extern const njs_value_t  njs_value_undefined;
808 extern const njs_value_t  njs_value_false;
809 extern const njs_value_t  njs_value_true;
810 extern const njs_value_t  njs_value_zero;
811 extern const njs_value_t  njs_value_nan;
812 extern const njs_value_t  njs_value_invalid;
813 
814 extern const njs_value_t  njs_string_empty;
815 extern const njs_value_t  njs_string_empty_regexp;
816 extern const njs_value_t  njs_string_comma;
817 extern const njs_value_t  njs_string_null;
818 extern const njs_value_t  njs_string_undefined;
819 extern const njs_value_t  njs_string_boolean;
820 extern const njs_value_t  njs_string_false;
821 extern const njs_value_t  njs_string_true;
822 extern const njs_value_t  njs_string_number;
823 extern const njs_value_t  njs_string_minus_zero;
824 extern const njs_value_t  njs_string_minus_infinity;
825 extern const njs_value_t  njs_string_plus_infinity;
826 extern const njs_value_t  njs_string_nan;
827 extern const njs_value_t  njs_string_symbol;
828 extern const njs_value_t  njs_string_string;
829 extern const njs_value_t  njs_string_data;
830 extern const njs_value_t  njs_string_type;
831 extern const njs_value_t  njs_string_name;
832 extern const njs_value_t  njs_string_external;
833 extern const njs_value_t  njs_string_invalid;
834 extern const njs_value_t  njs_string_object;
835 extern const njs_value_t  njs_string_function;
836 extern const njs_value_t  njs_string_memory_error;
837 
838 
839 njs_inline void
njs_set_boolean(njs_value_t * value,unsigned yn)840 njs_set_boolean(njs_value_t *value, unsigned yn)
841 {
842     const njs_value_t  *retval;
843 
844     /* Using const retval generates a better code at least on i386/amd64. */
845     retval = (yn) ? &njs_value_true : &njs_value_false;
846 
847     *value = *retval;
848 }
849 
850 
851 njs_inline void
njs_set_number(njs_value_t * value,double num)852 njs_set_number(njs_value_t *value, double num)
853 {
854     value->data.u.number = num;
855     value->type = NJS_NUMBER;
856     value->data.truth = njs_is_number_true(num);
857 }
858 
859 
860 njs_inline void
njs_set_int32(njs_value_t * value,int32_t num)861 njs_set_int32(njs_value_t *value, int32_t num)
862 {
863     value->data.u.number = num;
864     value->type = NJS_NUMBER;
865     value->data.truth = (num != 0);
866 }
867 
868 
869 njs_inline void
njs_set_uint32(njs_value_t * value,uint32_t num)870 njs_set_uint32(njs_value_t *value, uint32_t num)
871 {
872     value->data.u.number = num;
873     value->type = NJS_NUMBER;
874     value->data.truth = (num != 0);
875 }
876 
877 
878 njs_inline void
njs_set_symbol(njs_value_t * value,uint32_t symbol)879 njs_set_symbol(njs_value_t *value, uint32_t symbol)
880 {
881     value->data.magic32 = symbol;
882     value->type = NJS_SYMBOL;
883     value->data.truth = 1;
884 }
885 
886 
887 njs_inline void
njs_set_data(njs_value_t * value,void * data,njs_data_tag_t tag)888 njs_set_data(njs_value_t *value, void *data, njs_data_tag_t tag)
889 {
890     value->data.magic32 = tag;
891     value->data.u.data = data;
892     value->type = NJS_DATA;
893     value->data.truth = 1;
894 }
895 
896 
897 njs_inline void
njs_set_object(njs_value_t * value,njs_object_t * object)898 njs_set_object(njs_value_t *value, njs_object_t *object)
899 {
900     value->data.u.object = object;
901     value->type = NJS_OBJECT;
902     value->data.truth = 1;
903 }
904 
905 
906 njs_inline void
njs_set_type_object(njs_value_t * value,njs_object_t * object,njs_uint_t type)907 njs_set_type_object(njs_value_t *value, njs_object_t *object,
908     njs_uint_t type)
909 {
910     value->data.u.object = object;
911     value->type = type;
912     value->data.truth = 1;
913 }
914 
915 
916 njs_inline void
njs_set_array(njs_value_t * value,njs_array_t * array)917 njs_set_array(njs_value_t *value, njs_array_t *array)
918 {
919     value->data.u.array = array;
920     value->type = NJS_ARRAY;
921     value->data.truth = 1;
922 }
923 
924 
925 njs_inline void
njs_set_array_buffer(njs_value_t * value,njs_array_buffer_t * array)926 njs_set_array_buffer(njs_value_t *value, njs_array_buffer_t *array)
927 {
928     value->data.u.array_buffer = array;
929     value->type = NJS_ARRAY_BUFFER;
930     value->data.truth = 1;
931 }
932 
933 
934 njs_inline void
njs_set_typed_array(njs_value_t * value,njs_typed_array_t * array)935 njs_set_typed_array(njs_value_t *value, njs_typed_array_t *array)
936 {
937     value->data.u.typed_array = array;
938     value->type = NJS_TYPED_ARRAY;
939     value->data.truth = 1;
940 }
941 
942 
943 njs_inline void
njs_set_data_view(njs_value_t * value,njs_data_view_t * array)944 njs_set_data_view(njs_value_t *value, njs_data_view_t *array)
945 {
946     value->data.u.data_view = array;
947     value->type = NJS_DATA_VIEW;
948     value->data.truth = 1;
949 }
950 
951 
952 njs_inline void
njs_set_function(njs_value_t * value,njs_function_t * function)953 njs_set_function(njs_value_t *value, njs_function_t *function)
954 {
955     value->data.u.function = function;
956     value->type = NJS_FUNCTION;
957     value->data.truth = 1;
958 }
959 
960 
961 njs_inline void
njs_set_date(njs_value_t * value,njs_date_t * date)962 njs_set_date(njs_value_t *value, njs_date_t *date)
963 {
964     value->data.u.date = date;
965     value->type = NJS_DATE;
966     value->data.truth = 1;
967 }
968 
969 
970 njs_inline void
njs_set_promise(njs_value_t * value,njs_promise_t * promise)971 njs_set_promise(njs_value_t *value, njs_promise_t *promise)
972 {
973     value->data.u.promise = promise;
974     value->type = NJS_PROMISE;
975     value->data.truth = 1;
976 }
977 
978 
979 njs_inline void
njs_set_regexp(njs_value_t * value,njs_regexp_t * regexp)980 njs_set_regexp(njs_value_t *value, njs_regexp_t *regexp)
981 {
982     value->data.u.regexp = regexp;
983     value->type = NJS_REGEXP;
984     value->data.truth = 1;
985 }
986 
987 
988 njs_inline void
njs_set_object_value(njs_value_t * value,njs_object_value_t * object_value)989 njs_set_object_value(njs_value_t *value, njs_object_value_t *object_value)
990 {
991     value->data.u.object_value = object_value;
992     value->type = NJS_OBJECT_VALUE;
993     value->data.truth = 1;
994 }
995 
996 
997 #define njs_set_invalid(value)                                                \
998     (value)->type = NJS_INVALID
999 
1000 
1001 #if 0 /* GC: todo */
1002 
1003 #define njs_retain(value)                                                     \
1004     do {                                                                      \
1005         if ((value)->data.truth == NJS_STRING_LONG) {                         \
1006             njs_value_retain(value);                                          \
1007         }                                                                     \
1008     } while (0)
1009 
1010 
1011 #define njs_release(vm, value)                                                \
1012     do {                                                                      \
1013         if ((value)->data.truth == NJS_STRING_LONG) {                         \
1014             njs_value_release((vm), (value));                                 \
1015         }                                                                     \
1016     } while (0)
1017 
1018 #else
1019 
1020 #define njs_retain(value)
1021 #define njs_release(vm, value)
1022 
1023 #endif
1024 
1025 
1026 #define njs_property_query_init(pq, _query, _own)                             \
1027     do {                                                                      \
1028         (pq)->lhq.key.length = 0;                                             \
1029         (pq)->lhq.key.start = NULL;                                           \
1030         (pq)->lhq.value = NULL;                                               \
1031         /* FIXME: False-positive in MSAN?. */                                 \
1032         njs_msan_unpoison(&(pq)->key, sizeof(njs_value_t));                   \
1033         (pq)->own_whiteout = NULL;                                            \
1034         (pq)->query = _query;                                                 \
1035         (pq)->shared = 0;                                                     \
1036         (pq)->own = _own;                                                     \
1037     } while (0)
1038 
1039 
1040 void njs_value_retain(njs_value_t *value);
1041 void njs_value_release(njs_vm_t *vm, njs_value_t *value);
1042 njs_int_t njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst,
1043     njs_value_t *value, njs_uint_t hint);
1044 njs_array_t *njs_value_enumerate(njs_vm_t *vm, njs_value_t *value,
1045     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
1046 njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, njs_value_t *value,
1047     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
1048 njs_int_t njs_value_of(njs_vm_t *vm, njs_value_t *value, njs_value_t *retval);
1049 njs_int_t njs_value_length(njs_vm_t *vm, njs_value_t *value, int64_t *dst);
1050 const char *njs_type_string(njs_value_type_t type);
1051 
1052 njs_int_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
1053     const njs_value_t *src);
1054 njs_int_t njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
1055     const njs_value_t *src);
1056 double njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float);
1057 njs_int_t njs_int64_to_string(njs_vm_t *vm, njs_value_t *value, int64_t i64);
1058 
1059 njs_bool_t njs_string_eq(const njs_value_t *v1, const njs_value_t *v2);
1060 
1061 njs_int_t njs_property_query(njs_vm_t *vm, njs_property_query_t *pq,
1062     njs_value_t *value, njs_value_t *key);
1063 
1064 njs_int_t njs_value_property(njs_vm_t *vm, njs_value_t *value,
1065     njs_value_t *key, njs_value_t *retval);
1066 njs_int_t njs_value_property_set(njs_vm_t *vm, njs_value_t *value,
1067     njs_value_t *key, njs_value_t *setval);
1068 njs_int_t njs_value_property_delete(njs_vm_t *vm, njs_value_t *value,
1069     njs_value_t *key, njs_value_t *removed);
1070 njs_int_t njs_value_to_object(njs_vm_t *vm, njs_value_t *value);
1071 
1072 void njs_symbol_conversion_failed(njs_vm_t *vm, njs_bool_t to_string);
1073 
1074 njs_int_t njs_value_species_constructor(njs_vm_t *vm, njs_value_t *object,
1075     njs_value_t *default_constructor, njs_value_t *dst);
1076 
1077 njs_int_t njs_value_method(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
1078     njs_value_t *retval);
1079 
1080 
1081 njs_inline njs_int_t
njs_value_property_i64(njs_vm_t * vm,njs_value_t * value,int64_t index,njs_value_t * retval)1082 njs_value_property_i64(njs_vm_t *vm, njs_value_t *value, int64_t index,
1083     njs_value_t *retval)
1084 {
1085     njs_int_t    ret;
1086     njs_value_t  key;
1087 
1088     /* FIXME: False-positive in MSAN?. */
1089     njs_msan_unpoison(&key, sizeof(njs_value_t));
1090 
1091     ret = njs_int64_to_string(vm, &key, index);
1092     if (njs_slow_path(ret != NJS_OK)) {
1093         return ret;
1094     }
1095 
1096     return njs_value_property(vm, value, &key, retval);
1097 }
1098 
1099 
1100 njs_inline njs_int_t
njs_value_property_i64_set(njs_vm_t * vm,njs_value_t * value,int64_t index,njs_value_t * setval)1101 njs_value_property_i64_set(njs_vm_t *vm, njs_value_t *value, int64_t index,
1102     njs_value_t *setval)
1103 {
1104     njs_int_t    ret;
1105     njs_value_t  key;
1106 
1107     /* FIXME: False-positive in MSAN?. */
1108     njs_msan_unpoison(&key, sizeof(njs_value_t));
1109 
1110     ret = njs_int64_to_string(vm, &key, index);
1111     if (njs_slow_path(ret != NJS_OK)) {
1112         return ret;
1113     }
1114 
1115     return njs_value_property_set(vm, value, &key, setval);
1116 }
1117 
1118 
1119 njs_inline njs_int_t
njs_value_property_i64_delete(njs_vm_t * vm,njs_value_t * value,int64_t index,njs_value_t * removed)1120 njs_value_property_i64_delete(njs_vm_t *vm, njs_value_t *value, int64_t index,
1121     njs_value_t *removed)
1122 {
1123     njs_int_t    ret;
1124     njs_value_t  key;
1125 
1126     /* FIXME: False-positive in MSAN?. */
1127     njs_msan_unpoison(&key, sizeof(njs_value_t));
1128 
1129     ret = njs_int64_to_string(vm, &key, index);
1130     if (njs_slow_path(ret != NJS_OK)) {
1131         return ret;
1132     }
1133 
1134     return njs_value_property_delete(vm, value, &key, removed);
1135 }
1136 
1137 
1138 njs_inline njs_bool_t
njs_values_same_non_numeric(const njs_value_t * val1,const njs_value_t * val2)1139 njs_values_same_non_numeric(const njs_value_t *val1, const njs_value_t *val2)
1140 {
1141     if (njs_is_string(val1)) {
1142         return njs_string_eq(val1, val2);
1143     }
1144 
1145     if (njs_is_symbol(val1)) {
1146         return njs_symbol_eq(val1, val2);
1147     }
1148 
1149     return (njs_object(val1) == njs_object(val2));
1150 }
1151 
1152 
1153 njs_inline njs_bool_t
njs_values_strict_equal(const njs_value_t * val1,const njs_value_t * val2)1154 njs_values_strict_equal(const njs_value_t *val1, const njs_value_t *val2)
1155 {
1156     if (val1->type != val2->type) {
1157         return 0;
1158     }
1159 
1160     if (njs_is_numeric(val1)) {
1161 
1162         if (njs_is_undefined(val1)) {
1163             return 1;
1164         }
1165 
1166         /* Infinities are handled correctly by comparision. */
1167         return (njs_number(val1) == njs_number(val2));
1168     }
1169 
1170     return njs_values_same_non_numeric(val1, val2);
1171 }
1172 
1173 
1174 njs_inline njs_bool_t
njs_values_same(const njs_value_t * val1,const njs_value_t * val2)1175 njs_values_same(const njs_value_t *val1, const njs_value_t *val2)
1176 {
1177     double  num1, num2;
1178 
1179     if (val1->type != val2->type) {
1180         return 0;
1181     }
1182 
1183     if (njs_is_numeric(val1)) {
1184 
1185         if (njs_is_undefined(val1)) {
1186             return 1;
1187         }
1188 
1189         num1 = njs_number(val1);
1190         num2 = njs_number(val2);
1191 
1192         if (njs_slow_path(isnan(num1) && isnan(num2))) {
1193             return 1;
1194         }
1195 
1196         if (njs_slow_path(num1 == 0 && num2 == 0
1197                           && (signbit(num1) ^ signbit(num2))))
1198         {
1199             return 0;
1200         }
1201 
1202         /* Infinities are handled correctly by comparision. */
1203         return num1 == num2;
1204     }
1205 
1206     return njs_values_same_non_numeric(val1, val2);
1207 }
1208 
1209 
1210 njs_inline njs_bool_t
njs_values_same_zero(const njs_value_t * val1,const njs_value_t * val2)1211 njs_values_same_zero(const njs_value_t *val1, const njs_value_t *val2)
1212 {
1213     double  num1, num2;
1214 
1215     if (val1->type != val2->type) {
1216         return 0;
1217     }
1218 
1219     if (njs_is_numeric(val1)) {
1220 
1221         if (njs_is_undefined(val1)) {
1222             return 1;
1223         }
1224 
1225         num1 = njs_number(val1);
1226         num2 = njs_number(val2);
1227 
1228         if (njs_slow_path(isnan(num1) && isnan(num2))) {
1229             return 1;
1230         }
1231 
1232         /* Infinities are handled correctly by comparision. */
1233         return num1 == num2;
1234     }
1235 
1236     return njs_values_same_non_numeric(val1, val2);
1237 }
1238 
1239 
1240 #endif /* _NJS_VALUE_H_INCLUDED_ */
1241