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