1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7
8 #include <njs_main.h>
9
10
11 static njs_int_t njs_descriptor_prop(njs_vm_t *vm,
12 njs_object_prop_t *prop, const njs_value_t *desc);
13
14
15 njs_object_prop_t *
njs_object_prop_alloc(njs_vm_t * vm,const njs_value_t * name,const njs_value_t * value,uint8_t attributes)16 njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
17 const njs_value_t *value, uint8_t attributes)
18 {
19 njs_object_prop_t *prop;
20
21 prop = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
22 sizeof(njs_object_prop_t));
23
24 if (njs_fast_path(prop != NULL)) {
25 /* GC: retain. */
26 prop->value = *value;
27
28 /* GC: retain. */
29 prop->name = *name;
30
31 prop->type = NJS_PROPERTY;
32 prop->writable = attributes;
33 prop->enumerable = attributes;
34 prop->configurable = attributes;
35
36 njs_set_invalid(&prop->getter);
37 njs_set_invalid(&prop->setter);
38
39 return prop;
40 }
41
42 njs_memory_error(vm);
43
44 return NULL;
45 }
46
47
48 njs_int_t
njs_object_property(njs_vm_t * vm,const njs_value_t * value,njs_lvlhsh_query_t * lhq,njs_value_t * retval)49 njs_object_property(njs_vm_t *vm, const njs_value_t *value,
50 njs_lvlhsh_query_t *lhq, njs_value_t *retval)
51 {
52 njs_int_t ret;
53 njs_object_t *object;
54 njs_object_prop_t *prop;
55
56 object = njs_object(value);
57
58 do {
59 ret = njs_lvlhsh_find(&object->hash, lhq);
60
61 if (njs_fast_path(ret == NJS_OK)) {
62 goto found;
63 }
64
65 ret = njs_lvlhsh_find(&object->shared_hash, lhq);
66
67 if (njs_fast_path(ret == NJS_OK)) {
68 goto found;
69 }
70
71 object = object->__proto__;
72
73 } while (object != NULL);
74
75 njs_set_undefined(retval);
76
77 return NJS_DECLINED;
78
79 found:
80
81 prop = lhq->value;
82
83 if (njs_is_data_descriptor(prop)) {
84 *retval = prop->value;
85 return NJS_OK;
86 }
87
88 if (njs_is_undefined(&prop->getter)) {
89 njs_set_undefined(retval);
90 return NJS_OK;
91 }
92
93 return njs_function_apply(vm, njs_function(&prop->getter), value,
94 1, retval);
95 }
96
97
98 njs_object_prop_t *
njs_object_property_add(njs_vm_t * vm,njs_value_t * object,njs_value_t * key,njs_bool_t replace)99 njs_object_property_add(njs_vm_t *vm, njs_value_t *object, njs_value_t *key,
100 njs_bool_t replace)
101 {
102 njs_int_t ret;
103 njs_value_t key_value;
104 njs_object_prop_t *prop;
105 njs_lvlhsh_query_t lhq;
106
107 prop = njs_object_prop_alloc(vm, key, &njs_value_invalid, 1);
108 if (njs_slow_path(prop == NULL)) {
109 return NULL;
110 }
111
112 ret = njs_value_to_key(vm, &key_value, key);
113 if (njs_slow_path(ret != NJS_OK)) {
114 return NULL;
115 }
116
117 lhq.proto = &njs_object_hash_proto;
118 njs_string_get(&key_value, &lhq.key);
119 lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
120 lhq.value = prop;
121 lhq.replace = replace;
122 lhq.pool = vm->mem_pool;
123
124 ret = njs_lvlhsh_insert(njs_object_hash(object), &lhq);
125 if (njs_slow_path(ret != NJS_OK)) {
126 njs_internal_error(vm, "lvlhsh insert failed");
127 return NULL;
128 }
129
130 return prop;
131 }
132
133
134 /*
135 * ES5.1, 8.12.9: [[DefineOwnProperty]]
136 */
137 njs_int_t
njs_object_prop_define(njs_vm_t * vm,njs_value_t * object,njs_value_t * name,njs_value_t * value,njs_object_prop_define_t type)138 njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
139 njs_value_t *name, njs_value_t *value, njs_object_prop_define_t type)
140 {
141 uint32_t length;
142 njs_int_t ret;
143 njs_array_t *array;
144 njs_object_prop_t *prop, *prev;
145 njs_property_query_t pq;
146
147 static const njs_str_t length_key = njs_str("length");
148
149 if (njs_slow_path(!njs_is_key(name))) {
150 ret = njs_value_to_key(vm, name, name);
151 if (njs_slow_path(ret != NJS_OK)) {
152 return ret;
153 }
154 }
155
156 again:
157
158 njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 1);
159
160 ret = njs_property_query(vm, &pq, object, name);
161 if (njs_slow_path(ret == NJS_ERROR)) {
162 return ret;
163 }
164
165 prop = njs_object_prop_alloc(vm, name, &njs_value_invalid,
166 NJS_ATTRIBUTE_UNSET);
167 if (njs_slow_path(prop == NULL)) {
168 return NJS_ERROR;
169 }
170
171 switch (type) {
172
173 case NJS_OBJECT_PROP_DESCRIPTOR:
174 if (njs_descriptor_prop(vm, prop, value) != NJS_OK) {
175 return NJS_ERROR;
176 }
177
178 break;
179
180 case NJS_OBJECT_PROP_GETTER:
181 prop->getter = *value;
182 njs_set_invalid(&prop->setter);
183 prop->enumerable = NJS_ATTRIBUTE_TRUE;
184 prop->configurable = NJS_ATTRIBUTE_TRUE;
185
186 break;
187
188 case NJS_OBJECT_PROP_SETTER:
189 prop->setter = *value;
190 njs_set_invalid(&prop->getter);
191 prop->enumerable = NJS_ATTRIBUTE_TRUE;
192 prop->configurable = NJS_ATTRIBUTE_TRUE;
193
194 break;
195 }
196
197 if (njs_fast_path(ret == NJS_DECLINED)) {
198
199 set_prop:
200
201 if (!njs_object(object)->extensible) {
202 njs_key_string_get(vm, &pq.key, &pq.lhq.key);
203 njs_type_error(vm, "Cannot add property \"%V\", "
204 "object is not extensible", &pq.lhq.key);
205 return NJS_ERROR;
206 }
207
208 if (njs_slow_path(njs_is_typed_array(object)
209 && njs_is_string(name)))
210 {
211 /* Integer-Indexed Exotic Objects [[DefineOwnProperty]]. */
212 if (!isnan(njs_string_to_index(name))) {
213 njs_type_error(vm, "Invalid typed array index");
214 return NJS_ERROR;
215 }
216 }
217
218 /* 6.2.5.6 CompletePropertyDescriptor */
219
220 if (njs_is_accessor_descriptor(prop)) {
221 if (!njs_is_valid(&prop->getter)) {
222 njs_set_undefined(&prop->getter);
223 }
224
225 if (!njs_is_valid(&prop->setter)) {
226 njs_set_undefined(&prop->setter);
227 }
228
229 } else {
230 if (prop->writable == NJS_ATTRIBUTE_UNSET) {
231 prop->writable = 0;
232 }
233
234 if (!njs_is_valid(&prop->value)) {
235 njs_set_undefined(&prop->value);
236 }
237 }
238
239 if (prop->enumerable == NJS_ATTRIBUTE_UNSET) {
240 prop->enumerable = 0;
241 }
242
243 if (prop->configurable == NJS_ATTRIBUTE_UNSET) {
244 prop->configurable = 0;
245 }
246
247 if (njs_slow_path(pq.lhq.value != NULL)) {
248 prev = pq.lhq.value;
249
250 if (njs_slow_path(prev->type == NJS_WHITEOUT)) {
251 /* Previously deleted property. */
252 *prev = *prop;
253 }
254
255 } else {
256 pq.lhq.value = prop;
257 pq.lhq.replace = 0;
258 pq.lhq.pool = vm->mem_pool;
259
260 ret = njs_lvlhsh_insert(njs_object_hash(object), &pq.lhq);
261 if (njs_slow_path(ret != NJS_OK)) {
262 njs_internal_error(vm, "lvlhsh insert failed");
263 return NJS_ERROR;
264 }
265 }
266
267 return NJS_OK;
268 }
269
270 /* Updating existing prop. */
271
272 prev = pq.lhq.value;
273
274 switch (prev->type) {
275 case NJS_PROPERTY:
276 case NJS_PROPERTY_HANDLER:
277 break;
278
279 case NJS_PROPERTY_REF:
280 if (njs_is_accessor_descriptor(prop)
281 || prop->configurable == NJS_ATTRIBUTE_FALSE
282 || prop->enumerable == NJS_ATTRIBUTE_FALSE
283 || prop->writable == NJS_ATTRIBUTE_FALSE)
284 {
285 array = njs_array(object);
286 length = array->length;
287
288 ret = njs_array_convert_to_slow_array(vm, array);
289 if (njs_slow_path(ret != NJS_OK)) {
290 return ret;
291 }
292
293 ret = njs_array_length_redefine(vm, object, length);
294 if (njs_slow_path(ret != NJS_OK)) {
295 return ret;
296 }
297
298 goto again;
299 }
300
301 if (njs_is_valid(&prop->value)) {
302 *prev->value.data.u.value = prop->value;
303 } else {
304 njs_set_undefined(prev->value.data.u.value);
305 }
306
307 return NJS_OK;
308
309 case NJS_PROPERTY_TYPED_ARRAY_REF:
310 if (njs_is_accessor_descriptor(prop)) {
311 goto exception;
312 }
313
314 if (prop->configurable == NJS_ATTRIBUTE_TRUE ||
315 prop->enumerable == NJS_ATTRIBUTE_FALSE ||
316 prop->writable == NJS_ATTRIBUTE_FALSE)
317 {
318 goto exception;
319 }
320
321 if (njs_is_valid(&prop->value)) {
322 return njs_typed_array_set_value(vm, njs_typed_array(&prev->value),
323 prev->value.data.magic32,
324 &prop->value);
325 }
326
327 return NJS_OK;
328
329 default:
330 njs_internal_error(vm, "unexpected property type \"%s\" "
331 "while defining property",
332 njs_prop_type_string(prev->type));
333
334 return NJS_ERROR;
335 }
336
337 /* 9.1.6.3 ValidateAndApplyPropertyDescriptor */
338
339 if (!prev->configurable) {
340
341 if (prop->configurable == NJS_ATTRIBUTE_TRUE) {
342 goto exception;
343 }
344
345 if (prop->enumerable != NJS_ATTRIBUTE_UNSET
346 && prev->enumerable != prop->enumerable)
347 {
348 goto exception;
349 }
350 }
351
352 if (njs_is_generic_descriptor(prop)) {
353 goto done;
354 }
355
356 if (njs_is_data_descriptor(prev) != njs_is_data_descriptor(prop)) {
357 if (!prev->configurable) {
358 goto exception;
359 }
360
361 /*
362 * 6.b-c Preserve the existing values of the converted property's
363 * [[Configurable]] and [[Enumerable]] attributes and set the rest of
364 * the property's attributes to their default values.
365 */
366
367 if (njs_is_data_descriptor(prev)) {
368 njs_set_undefined(&prev->getter);
369 njs_set_undefined(&prev->setter);
370
371 njs_set_invalid(&prev->value);
372 prev->writable = NJS_ATTRIBUTE_UNSET;
373
374 } else {
375 njs_set_undefined(&prev->value);
376 prev->writable = NJS_ATTRIBUTE_FALSE;
377
378 njs_set_invalid(&prev->getter);
379 njs_set_invalid(&prev->setter);
380 }
381
382
383 } else if (njs_is_data_descriptor(prev)
384 && njs_is_data_descriptor(prop))
385 {
386 if (!prev->configurable && !prev->writable) {
387 if (prop->writable == NJS_ATTRIBUTE_TRUE) {
388 goto exception;
389 }
390
391 if (njs_is_valid(&prop->value)
392 && prev->type != NJS_PROPERTY_HANDLER
393 && !njs_values_same(&prop->value, &prev->value))
394 {
395 goto exception;
396 }
397 }
398
399 } else {
400 if (!prev->configurable) {
401 if (njs_is_valid(&prop->getter)
402 && !njs_values_strict_equal(&prop->getter, &prev->getter))
403 {
404 goto exception;
405 }
406
407 if (njs_is_valid(&prop->setter)
408 && !njs_values_strict_equal(&prop->setter, &prev->setter))
409 {
410 goto exception;
411 }
412 }
413 }
414
415 done:
416
417 if (njs_is_valid(&prop->value) || njs_is_accessor_descriptor(prop)) {
418 if (prev->type == NJS_PROPERTY_HANDLER) {
419 if (prev->writable) {
420 ret = prev->value.data.u.prop_handler(vm, prev, object,
421 &prop->value,
422 &vm->retval);
423 if (njs_slow_path(ret == NJS_ERROR)) {
424 return ret;
425 }
426
427 if (ret == NJS_DECLINED) {
428 pq.lhq.value = NULL;
429 goto set_prop;
430 }
431 }
432
433 } else {
434 if (njs_slow_path(pq.lhq.key_hash == NJS_LENGTH_HASH)) {
435 if (njs_strstr_eq(&pq.lhq.key, &length_key)) {
436 ret = njs_array_length_set(vm, object, prev, &prop->value);
437 if (ret != NJS_DECLINED) {
438 return ret;
439 }
440 }
441 }
442
443 prev->value = prop->value;
444 }
445 }
446
447 /*
448 * 9. For each field of Desc that is present, set the corresponding
449 * attribute of the property named P of object O to the value of the field.
450 */
451
452 if (njs_is_valid(&prop->getter)) {
453 prev->getter = prop->getter;
454 }
455
456 if (njs_is_valid(&prop->setter)) {
457 prev->setter = prop->setter;
458 }
459
460 if (prop->writable != NJS_ATTRIBUTE_UNSET) {
461 prev->writable = prop->writable;
462 }
463
464 if (prop->enumerable != NJS_ATTRIBUTE_UNSET) {
465 prev->enumerable = prop->enumerable;
466 }
467
468 if (prop->configurable != NJS_ATTRIBUTE_UNSET) {
469 prev->configurable = prop->configurable;
470 }
471
472 return NJS_OK;
473
474 exception:
475
476 njs_key_string_get(vm, &pq.key, &pq.lhq.key);
477 njs_type_error(vm, "Cannot redefine property: \"%V\"", &pq.lhq.key);
478
479 return NJS_ERROR;
480 }
481
482
483 njs_int_t
njs_prop_private_copy(njs_vm_t * vm,njs_property_query_t * pq)484 njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
485 {
486 njs_int_t ret;
487 njs_value_t *value;
488 njs_object_t *object;
489 njs_function_t *function;
490 njs_object_prop_t *prop, *shared;
491
492 prop = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
493 sizeof(njs_object_prop_t));
494 if (njs_slow_path(prop == NULL)) {
495 njs_memory_error(vm);
496 return NJS_ERROR;
497 }
498
499 shared = pq->lhq.value;
500 *prop = *shared;
501
502 pq->lhq.replace = 0;
503 pq->lhq.value = prop;
504 pq->lhq.pool = vm->mem_pool;
505
506 ret = njs_lvlhsh_insert(&pq->prototype->hash, &pq->lhq);
507 if (njs_slow_path(ret != NJS_OK)) {
508 njs_internal_error(vm, "lvlhsh insert failed");
509 return NJS_ERROR;
510 }
511
512 if (njs_is_accessor_descriptor(prop)) {
513 if (njs_is_function(&prop->getter)) {
514 function = njs_function_value_copy(vm, &prop->getter);
515 if (njs_slow_path(function == NULL)) {
516 return NJS_ERROR;
517 }
518
519 if (njs_is_function(&prop->setter)
520 && function->native && njs_function(&prop->setter)->native
521 && function->u.native == njs_function(&prop->setter)->u.native)
522 {
523 prop->setter = prop->getter;
524 return NJS_OK;
525 }
526 }
527
528 if (njs_is_function(&prop->setter)) {
529 function = njs_function_value_copy(vm, &prop->setter);
530 if (njs_slow_path(function == NULL)) {
531 return NJS_ERROR;
532 }
533 }
534
535 return NJS_OK;
536 }
537
538 value = &prop->value;
539
540 switch (value->type) {
541 case NJS_OBJECT:
542 case NJS_OBJECT_VALUE:
543 object = njs_object_value_copy(vm, value);
544 if (njs_slow_path(object == NULL)) {
545 return NJS_ERROR;
546 }
547
548 value->data.u.object = object;
549 return NJS_OK;
550
551 case NJS_FUNCTION:
552 function = njs_function_value_copy(vm, &prop->value);
553 if (njs_slow_path(function == NULL)) {
554 return NJS_ERROR;
555 }
556
557 return njs_function_name_set(vm, function, &prop->name, NULL);
558
559 default:
560 break;
561 }
562
563 return NJS_OK;
564 }
565
566
567 static njs_int_t
njs_descriptor_prop(njs_vm_t * vm,njs_object_prop_t * prop,const njs_value_t * desc)568 njs_descriptor_prop(njs_vm_t *vm, njs_object_prop_t *prop,
569 const njs_value_t *desc)
570 {
571 njs_int_t ret;
572 njs_bool_t data, accessor;
573 njs_value_t value;
574 njs_lvlhsh_query_t lhq;
575
576 static const njs_value_t get_string = njs_string("get");
577
578 if (!njs_is_object(desc)) {
579 njs_type_error(vm, "property descriptor must be an object");
580 return NJS_ERROR;
581 }
582
583 data = 0;
584 accessor = 0;
585
586 njs_object_property_init(&lhq, &get_string, NJS_GET_HASH);
587
588 ret = njs_object_property(vm, desc, &lhq, &value);
589
590 if (njs_slow_path(ret == NJS_ERROR)) {
591 return NJS_ERROR;
592 }
593
594 if (ret == NJS_OK) {
595 if (njs_is_defined(&value) && !njs_is_function(&value)) {
596 njs_type_error(vm, "Getter must be a function");
597 return NJS_ERROR;
598 }
599
600 accessor = 1;
601 prop->getter = value;
602
603 } else {
604 /* NJS_DECLINED */
605 njs_set_invalid(&prop->getter);
606 }
607
608 lhq.key = njs_str_value("set");
609 lhq.key_hash = NJS_SET_HASH;
610
611 ret = njs_object_property(vm, desc, &lhq, &value);
612
613 if (njs_slow_path(ret == NJS_ERROR)) {
614 return ret;
615 }
616
617 if (ret == NJS_OK) {
618 if (njs_is_defined(&value) && !njs_is_function(&value)) {
619 njs_type_error(vm, "Setter must be a function");
620 return NJS_ERROR;
621 }
622
623 accessor = 1;
624 prop->setter = value;
625
626 } else {
627 /* NJS_DECLINED */
628 njs_set_invalid(&prop->setter);
629 }
630
631 lhq.key = njs_str_value("value");
632 lhq.key_hash = NJS_VALUE_HASH;
633
634 ret = njs_object_property(vm, desc, &lhq, &value);
635
636 if (njs_slow_path(ret == NJS_ERROR)) {
637 return ret;
638 }
639
640 if (ret == NJS_OK) {
641 data = 1;
642 prop->value = value;
643 }
644
645 lhq.key = njs_str_value("writable");
646 lhq.key_hash = NJS_WRITABABLE_HASH;
647
648 ret = njs_object_property(vm, desc, &lhq, &value);
649
650 if (njs_slow_path(ret == NJS_ERROR)) {
651 return ret;
652 }
653
654 if (ret == NJS_OK) {
655 data = 1;
656 prop->writable = njs_is_true(&value);
657 }
658
659 lhq.key = njs_str_value("enumerable");
660 lhq.key_hash = NJS_ENUMERABLE_HASH;
661
662 ret = njs_object_property(vm, desc, &lhq, &value);
663
664 if (njs_slow_path(ret == NJS_ERROR)) {
665 return ret;
666 }
667
668 if (ret == NJS_OK) {
669 prop->enumerable = njs_is_true(&value);
670 }
671
672 lhq.key = njs_str_value("configurable");
673 lhq.key_hash = NJS_CONFIGURABLE_HASH;
674
675 ret = njs_object_property(vm, desc, &lhq, &value);
676
677 if (njs_slow_path(ret == NJS_ERROR)) {
678 return ret;
679 }
680
681 if (ret == NJS_OK) {
682 prop->configurable = njs_is_true(&value);
683 }
684
685 if (accessor && data) {
686 njs_type_error(vm, "Cannot both specify accessors "
687 "and a value or writable attribute");
688 return NJS_ERROR;
689 }
690
691 return NJS_OK;
692 }
693
694
695 static const njs_value_t njs_object_value_string = njs_string("value");
696 static const njs_value_t njs_object_get_string = njs_string("get");
697 static const njs_value_t njs_object_set_string = njs_string("set");
698 static const njs_value_t njs_object_writable_string =
699 njs_string("writable");
700 static const njs_value_t njs_object_enumerable_string =
701 njs_string("enumerable");
702 static const njs_value_t njs_object_configurable_string =
703 njs_string("configurable");
704
705
706 njs_int_t
njs_object_prop_descriptor(njs_vm_t * vm,njs_value_t * dest,njs_value_t * value,njs_value_t * key)707 njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest,
708 njs_value_t *value, njs_value_t *key)
709 {
710 njs_int_t ret;
711 njs_object_t *desc;
712 njs_object_prop_t *pr, *prop;
713 const njs_value_t *setval;
714 njs_lvlhsh_query_t lhq;
715 njs_property_query_t pq;
716
717 njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 1);
718
719 if (njs_slow_path(!njs_is_key(key))) {
720 ret = njs_value_to_key(vm, key, key);
721 if (njs_slow_path(ret != NJS_OK)) {
722 return ret;
723 }
724 }
725
726 ret = njs_property_query(vm, &pq, value, key);
727
728 switch (ret) {
729 case NJS_OK:
730 prop = pq.lhq.value;
731
732 switch (prop->type) {
733 case NJS_PROPERTY:
734 break;
735
736 case NJS_PROPERTY_HANDLER:
737 pq.scratch = *prop;
738 prop = &pq.scratch;
739 ret = prop->value.data.u.prop_handler(vm, prop, value, NULL,
740 &prop->value);
741 if (njs_slow_path(ret == NJS_ERROR)) {
742 return ret;
743 }
744
745 break;
746
747 default:
748 njs_type_error(vm, "unexpected property type: %s",
749 njs_prop_type_string(prop->type));
750 return NJS_ERROR;
751 }
752
753 break;
754
755 case NJS_DECLINED:
756 njs_set_undefined(dest);
757 return NJS_OK;
758
759 case NJS_ERROR:
760 default:
761 return ret;
762 }
763
764 desc = njs_object_alloc(vm);
765 if (njs_slow_path(desc == NULL)) {
766 return NJS_ERROR;
767 }
768
769 lhq.proto = &njs_object_hash_proto;
770 lhq.replace = 0;
771 lhq.pool = vm->mem_pool;
772
773 if (njs_is_data_descriptor(prop)) {
774
775 lhq.key = njs_str_value("value");
776 lhq.key_hash = NJS_VALUE_HASH;
777
778 pr = njs_object_prop_alloc(vm, &njs_object_value_string, &prop->value,
779 1);
780 if (njs_slow_path(pr == NULL)) {
781 return NJS_ERROR;
782 }
783
784 lhq.value = pr;
785
786 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
787 if (njs_slow_path(ret != NJS_OK)) {
788 njs_internal_error(vm, "lvlhsh insert failed");
789 return NJS_ERROR;
790 }
791
792 lhq.key = njs_str_value("writable");
793 lhq.key_hash = NJS_WRITABABLE_HASH;
794
795 setval = (prop->writable == 1) ? &njs_value_true : &njs_value_false;
796
797 pr = njs_object_prop_alloc(vm, &njs_object_writable_string, setval, 1);
798 if (njs_slow_path(pr == NULL)) {
799 return NJS_ERROR;
800 }
801
802 lhq.value = pr;
803
804 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
805 if (njs_slow_path(ret != NJS_OK)) {
806 njs_internal_error(vm, "lvlhsh insert failed");
807 return NJS_ERROR;
808 }
809
810 } else {
811
812 lhq.key = njs_str_value("get");
813 lhq.key_hash = NJS_GET_HASH;
814
815 pr = njs_object_prop_alloc(vm, &njs_object_get_string, &prop->getter,
816 1);
817 if (njs_slow_path(pr == NULL)) {
818 return NJS_ERROR;
819 }
820
821 lhq.value = pr;
822
823 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
824 if (njs_slow_path(ret != NJS_OK)) {
825 njs_internal_error(vm, "lvlhsh insert failed");
826 return NJS_ERROR;
827 }
828
829 lhq.key = njs_str_value("set");
830 lhq.key_hash = NJS_SET_HASH;
831
832 pr = njs_object_prop_alloc(vm, &njs_object_set_string, &prop->setter,
833 1);
834 if (njs_slow_path(pr == NULL)) {
835 return NJS_ERROR;
836 }
837
838 lhq.value = pr;
839
840 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
841 if (njs_slow_path(ret != NJS_OK)) {
842 njs_internal_error(vm, "lvlhsh insert failed");
843 return NJS_ERROR;
844 }
845 }
846
847 lhq.key = njs_str_value("enumerable");
848 lhq.key_hash = NJS_ENUMERABLE_HASH;
849
850 setval = (prop->enumerable == 1) ? &njs_value_true : &njs_value_false;
851
852 pr = njs_object_prop_alloc(vm, &njs_object_enumerable_string, setval, 1);
853 if (njs_slow_path(pr == NULL)) {
854 return NJS_ERROR;
855 }
856
857 lhq.value = pr;
858
859 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
860 if (njs_slow_path(ret != NJS_OK)) {
861 njs_internal_error(vm, "lvlhsh insert failed");
862 return NJS_ERROR;
863 }
864
865 lhq.key = njs_str_value("configurable");
866 lhq.key_hash = NJS_CONFIGURABLE_HASH;
867
868 setval = (prop->configurable == 1) ? &njs_value_true : &njs_value_false;
869
870 pr = njs_object_prop_alloc(vm, &njs_object_configurable_string, setval, 1);
871 if (njs_slow_path(pr == NULL)) {
872 return NJS_ERROR;
873 }
874
875 lhq.value = pr;
876
877 ret = njs_lvlhsh_insert(&desc->hash, &lhq);
878 if (njs_slow_path(ret != NJS_OK)) {
879 njs_internal_error(vm, "lvlhsh insert failed");
880 return NJS_ERROR;
881 }
882
883 njs_set_object(dest, desc);
884
885 return NJS_OK;
886 }
887
888
889 const char *
njs_prop_type_string(njs_object_prop_type_t type)890 njs_prop_type_string(njs_object_prop_type_t type)
891 {
892 switch (type) {
893 case NJS_PROPERTY_REF:
894 return "property_ref";
895
896 case NJS_PROPERTY_HANDLER:
897 return "property handler";
898
899 case NJS_WHITEOUT:
900 return "whiteout";
901
902 case NJS_PROPERTY:
903 return "property";
904
905 default:
906 return "unknown";
907 }
908 }
909
910
911 njs_int_t
njs_object_prop_init(njs_vm_t * vm,const njs_object_init_t * init,const njs_object_prop_t * base,njs_value_t * value,njs_value_t * retval)912 njs_object_prop_init(njs_vm_t *vm, const njs_object_init_t* init,
913 const njs_object_prop_t *base, njs_value_t *value, njs_value_t *retval)
914 {
915 njs_int_t ret;
916 njs_object_t *object;
917 njs_object_prop_t *prop;
918 njs_lvlhsh_query_t lhq;
919
920 object = njs_object_alloc(vm);
921 if (object == NULL) {
922 return NJS_ERROR;
923 }
924
925 ret = njs_object_hash_create(vm, &object->hash, init->properties,
926 init->items);
927 if (njs_slow_path(ret != NJS_OK)) {
928 return NJS_ERROR;
929 }
930
931 prop = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
932 sizeof(njs_object_prop_t));
933 if (njs_slow_path(prop == NULL)) {
934 njs_memory_error(vm);
935 return NJS_ERROR;
936 }
937
938 *prop = *base;
939
940 prop->type = NJS_PROPERTY;
941 njs_set_object(&prop->value, object);
942
943 lhq.proto = &njs_object_hash_proto;
944 njs_string_get(&prop->name, &lhq.key);
945 lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
946 lhq.value = prop;
947 lhq.replace = 1;
948 lhq.pool = vm->mem_pool;
949
950 ret = njs_lvlhsh_insert(njs_object_hash(value), &lhq);
951 if (njs_fast_path(ret == NJS_OK)) {
952 *retval = prop->value;
953 return NJS_OK;
954 }
955
956 njs_internal_error(vm, "lvlhsh insert failed");
957
958 return NJS_ERROR;
959 }
960