• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/types.c

  1 /*
  2  * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <stdarg.h>
 18 #include <stdlib.h>
 19 #include <assert.h>
 20 #include <errno.h>
 21 #include <math.h>
 22 #include <ctype.h>
 23 #include <float.h>
 24 
 25 #include "json-c-compat.h"
 26 
 27 #include "ucode/types.h"
 28 #include "ucode/util.h"
 29 #include "ucode/vm.h"
 30 #include "ucode/program.h"
 31 
 32 static char *uc_default_search_path[] = { LIB_SEARCH_PATH };
 33 
 34 uc_parse_config_t uc_default_parse_config = {
 35         .module_search_path = {
 36                 .count = ARRAY_SIZE(uc_default_search_path),
 37                 .entries = uc_default_search_path
 38         }
 39 };
 40 
 41 uc_type_t
 42 ucv_type(uc_value_t *uv)
 43 {
 44         uc_type_t type = ((uintptr_t)uv & 3);
 45 
 46         if (type == UC_NULL && uv != NULL)
 47                 type = uv->type;
 48 
 49         return type;
 50 }
 51 
 52 const char *
 53 ucv_typename(uc_value_t *uv)
 54 {
 55         switch (ucv_type(uv)) {
 56         case UC_NULL:      return "null";
 57         case UC_INTEGER:   return "integer";
 58         case UC_BOOLEAN:   return "boolean";
 59         case UC_STRING:    return "string";
 60         case UC_DOUBLE:    return "double";
 61         case UC_ARRAY:     return "array";
 62         case UC_OBJECT:    return "object";
 63         case UC_REGEXP:    return "regexp";
 64         case UC_CFUNCTION: return "cfunction";
 65         case UC_CLOSURE:   return "closure";
 66         case UC_UPVALUE:   return "upvalue";
 67         case UC_RESOURCE:  return "resource";
 68         case UC_PROGRAM:   return "program";
 69         case UC_SOURCE:    return "source";
 70         }
 71 
 72         return "unknown";
 73 }
 74 
 75 void
 76 ucv_unref(uc_weakref_t *ref)
 77 {
 78         ref->prev->next = ref->next;
 79         ref->next->prev = ref->prev;
 80 }
 81 
 82 static void
 83 ucv_ref_tail(uc_weakref_t *head, uc_weakref_t *item)
 84 {
 85         item->next = head;
 86         item->prev = head->prev;
 87         head->prev->next = item;
 88         head->prev = item;
 89 }
 90 
 91 void
 92 ucv_ref(uc_weakref_t *head, uc_weakref_t *item)
 93 {
 94         item->next = head->next;
 95         item->prev = head;
 96         head->next->prev = item;
 97         head->next = item;
 98 }
 99 
100 static uc_value_t **
101 ucv_resource_values(uc_resource_ext_t *res)
102 {
103         void *data;
104 
105         if (!ucv_resource_is_extended((uc_value_t *)res) || !res->uvcount)
106                 return NULL;
107 
108         data = res + 1;
109         data += res->datasize * 8;
110 
111         return data;
112 }
113 
114 #if 0
115 static uc_weakref_t *
116 ucv_get_weakref(uc_value_t *uv)
117 {
118         switch (ucv_type(uv)) {
119         case UC_ARRAY:
120                 return &((uc_array_t *)uv)->ref;
121 
122         case UC_OBJECT:
123                 return &((uc_object_t *)uv)->ref;
124 
125         case UC_CLOSURE:
126                 return &((uc_closure_t *)uv)->ref;
127 
128         default:
129                 return NULL;
130         }
131 }
132 #endif
133 
134 static void
135 ucv_put_value(uc_value_t *uv, bool retain)
136 {
137         if (uv == NULL || (uintptr_t)uv & 3)
138                 return;
139 
140         assert(uv->type == UC_NULL || uv->refcount > 0);
141 
142         if (uv->refcount > 0)
143                 uv->refcount--;
144 
145         if (uv->refcount == 0)
146                 ucv_free(uv, retain);
147 }
148 
149 static void
150 ucv_gc_mark(uc_value_t *uv);
151 
152 static void
153 ucv_gc_mark(uc_value_t *uv)
154 {
155         uc_function_t *function;
156         uc_closure_t *closure;
157         uc_upvalref_t *upval;
158         uc_object_t *object;
159         uc_array_t *array;
160         uc_resource_type_t *restype;
161         uc_program_t *program;
162         uc_value_t **values;
163         struct lh_entry *entry;
164         size_t i;
165 
166         if (ucv_is_marked(uv))
167                 return;
168 
169         switch (ucv_type(uv)) {
170         case UC_ARRAY:
171                 array = (uc_array_t *)uv;
172 
173                 if (array->ref.next)
174                         ucv_set_mark(uv);
175 
176                 ucv_gc_mark(array->proto);
177 
178                 for (i = 0; i < array->count; i++)
179                         ucv_gc_mark(array->entries[i]);
180 
181                 break;
182 
183         case UC_OBJECT:
184                 object = (uc_object_t *)uv;
185 
186                 if (object->ref.next)
187                         ucv_set_mark(uv);
188 
189                 ucv_gc_mark(object->proto);
190 
191                 lh_foreach(object->table, entry)
192                         ucv_gc_mark((uc_value_t *)lh_entry_v(entry));
193 
194                 break;
195 
196         case UC_CLOSURE:
197                 closure = (uc_closure_t *)uv;
198                 function = closure->function;
199 
200                 if (closure->ref.next)
201                         ucv_set_mark(uv);
202 
203                 for (i = 0; i < function->nupvals; i++)
204                         ucv_gc_mark(&closure->upvals[i]->header);
205 
206                 ucv_gc_mark(&function->program->header);
207 
208                 break;
209 
210         case UC_UPVALUE:
211                 upval = (uc_upvalref_t *)uv;
212                 ucv_gc_mark(upval->value);
213                 break;
214 
215         case UC_RESOURCE:
216                 if (uv->ext_flag) {
217                         uc_resource_ext_t *res = (uc_resource_ext_t *)uv;
218 
219                         if (res->ref.next)
220                                 ucv_set_mark(uv);
221 
222                         values = ucv_resource_values(res);
223                         if (!values)
224                                 break;
225 
226                         for (i = 0; i < res->uvcount; i++)
227                                 ucv_gc_mark(values[i]);
228                 }
229 
230                 restype = ucv_resource_type(uv);
231                 if (restype)
232                         ucv_gc_mark(restype->proto);
233 
234                 break;
235 
236         case UC_PROGRAM:
237                 program = (uc_program_t *)uv;
238 
239                 for (i = 0; i < program->sources.count; i++)
240                         ucv_gc_mark(&program->sources.entries[i]->header);
241 
242                 for (i = 0; i < program->exports.count; i++)
243                         ucv_gc_mark(&program->exports.entries[i]->header);
244 
245                 break;
246 
247         default:
248                 break;
249         }
250 }
251 
252 void
253 ucv_free(uc_value_t *uv, bool retain)
254 {
255         uc_function_t *function;
256         uc_closure_t *closure;
257         uc_program_t *program;
258         uc_upvalref_t *upval;
259         uc_source_t *source;
260         uc_regexp_t *regexp;
261         uc_object_t *object;
262         uc_array_t *array;
263         uc_weakref_t *ref;
264         size_t i;
265 
266         if (uv == NULL || (uintptr_t)uv & 3)
267                 return;
268 
269         if (uv->mark)
270                 return;
271 
272         uv->mark = true;
273 
274         ref = NULL;
275 
276         switch (uv->type) {
277         case UC_ARRAY:
278                 array = (uc_array_t *)uv;
279                 ref = &array->ref;
280                 ucv_put_value(array->proto, retain);
281 
282                 for (i = 0; i < array->count; i++)
283                         ucv_put_value(array->entries[i], retain);
284 
285                 uc_vector_clear(array);
286                 break;
287 
288         case UC_OBJECT:
289                 object = (uc_object_t *)uv;
290                 ref = &object->ref;
291                 ucv_put_value(object->proto, retain);
292                 lh_table_free(object->table);
293                 break;
294 
295         case UC_REGEXP:
296                 regexp = (uc_regexp_t *)uv;
297                 regfree(&regexp->regexp);
298                 break;
299 
300         case UC_CLOSURE:
301                 closure = (uc_closure_t *)uv;
302                 function = closure->function;
303                 ref = &closure->ref;
304 
305                 for (i = 0; i < function->nupvals; i++)
306                         if (closure->upvals[i])
307                                 ucv_put_value(&closure->upvals[i]->header, retain);
308 
309                 ucv_put_value(&function->program->header, retain);
310                 break;
311 
312         case UC_RESOURCE:
313                 if (uv->ext_flag) {
314                         uc_resource_ext_t *res = (uc_resource_ext_t *)uv;
315                         uc_value_t **values;
316 
317                         values = ucv_resource_values(res);
318                         if (values) {
319                                 for (i = 0; i < res->uvcount; i++)
320                                         ucv_put_value(values[i], retain);
321                         }
322 
323                         if (res->type && res->type->free) {
324                                 void *data = res + 1;
325 
326                                 res->type->free(data);
327                         }
328 
329                         ref = &res->ref;
330                 }
331                 else {
332                         uc_resource_t *res = (uc_resource_t *)uv;
333 
334                         if (res->type && res->type->free)
335                                 res->type->free(res->data);
336                 }
337                 break;
338 
339         case UC_UPVALUE:
340                 upval = (uc_upvalref_t *)uv;
341                 ucv_put_value(upval->value, retain);
342                 break;
343 
344         case UC_PROGRAM:
345                 program = (uc_program_t *)uv;
346 
347                 uc_program_function_foreach_safe(program, func)
348                         uc_program_function_free(func);
349 
350                 uc_vallist_free(&program->constants);
351 
352                 for (i = 0; i < program->sources.count; i++)
353                         ucv_put_value(&program->sources.entries[i]->header, retain);
354 
355                 for (i = 0; i < program->exports.count; i++)
356                         ucv_put_value(&program->exports.entries[i]->header, retain);
357 
358                 uc_vector_clear(&program->sources);
359                 uc_vector_clear(&program->exports);
360                 break;
361 
362         case UC_SOURCE:
363                 source = (uc_source_t *)uv;
364 
365                 if (source->runpath != source->filename)
366                         free(source->runpath);
367 
368                 for (i = 0; i < source->exports.count; i++)
369                         ucv_put(source->exports.entries[i]);
370 
371                 uc_vector_clear(&source->lineinfo);
372                 uc_vector_clear(&source->exports);
373                 fclose(source->fp);
374                 free(source->buffer);
375                 break;
376         }
377 
378         if (!ref || !retain) {
379                 if (ref && ref->prev && ref->next)
380                         ucv_unref(ref);
381 
382                 free(uv);
383         }
384         else {
385                 uv->type = UC_NULL;
386         }
387 }
388 
389 void
390 ucv_put(uc_value_t *uv)
391 {
392         ucv_put_value(uv, false);
393 }
394 
395 uc_value_t *
396 ucv_get(uc_value_t *uv)
397 {
398         if (uv == NULL || (uintptr_t)uv & 3)
399                 return uv;
400 
401         assert(uv->refcount < 0x03ffffff);
402 
403         uv->refcount++;
404 
405         return uv;
406 }
407 
408 uc_value_t *
409 ucv_boolean_new(bool val)
410 {
411         uintptr_t pv = UC_BOOLEAN | (val << 2);
412 
413         return (uc_value_t *)pv;
414 }
415 
416 bool
417 ucv_boolean_get(uc_value_t *uv)
418 {
419         uintptr_t pv = (uintptr_t)uv;
420 
421         if ((pv & 3) == UC_BOOLEAN)
422                 return (pv >> 2) & 1;
423 
424         return false;
425 }
426 
427 
428 uc_value_t *
429 ucv_string_new(const char *str)
430 {
431         return ucv_string_new_length(str, strlen(str));
432 }
433 
434 uc_value_t *
435 ucv_string_new_length(const char *str, size_t length)
436 {
437         uc_string_t *ustr;
438         uintptr_t pv;
439         size_t i;
440         char *s;
441 
442         if ((length + 1) < sizeof(void *)) {
443                 pv = UC_STRING | (length << 2);
444 
445 #if __BYTE_ORDER == __LITTLE_ENDIAN
446                 s = (char *)&pv + 1;
447 #else
448                 s = (char *)&pv;
449 #endif
450 
451                 for (i = 0; i < length; i++)
452                         s[i] = str[i];
453 
454                 return (uc_value_t *)pv;
455         }
456 
457         ustr = xalloc(sizeof(*ustr) + length + 1);
458         ustr->header.type = UC_STRING;
459         ustr->header.refcount = 1;
460         ustr->length = length;
461         memcpy(ustr->str, str, length);
462 
463         return &ustr->header;
464 }
465 
466 uc_stringbuf_t *
467 ucv_stringbuf_new(void)
468 {
469         uc_stringbuf_t *sb = xprintbuf_new();
470         uc_string_t ustr = {
471                 .header = {
472                         .type = UC_STRING,
473                         .refcount = 1
474                 }
475         };
476 
477         printbuf_memappend_fast(sb, (char *)&ustr, (int)sizeof(ustr));
478 
479         return sb;
480 }
481 
482 uc_value_t *
483 ucv_stringbuf_finish(uc_stringbuf_t *sb)
484 {
485         uc_string_t *ustr = (uc_string_t *)sb->buf;
486 
487         ustr->length = printbuf_length(sb) - offsetof(uc_string_t, str);
488 
489         free(sb);
490 
491         return &ustr->header;
492 }
493 
494 char *
495 _ucv_string_get(uc_value_t **uv)
496 {
497         uc_string_t *str;
498 
499         switch ((uintptr_t)*uv & 3) {
500         case UC_STRING:
501 #if __BYTE_ORDER == __LITTLE_ENDIAN
502                 return (char *)uv + 1;
503 #else
504                 return (char *)uv;
505 #endif
506 
507         case UC_NULL:
508                 if (*uv != NULL && (*uv)->type == UC_STRING) {
509                         str = (uc_string_t *)*uv;
510 
511                         return str->str;
512                 }
513         }
514 
515         return NULL;
516 }
517 
518 size_t
519 ucv_string_length(uc_value_t *uv)
520 {
521         uc_string_t *str = (uc_string_t *)uv;
522         uintptr_t pv = (uintptr_t)uv;
523 
524         if ((pv & 3) == UC_STRING)
525                 return (pv & 0xff) >> 2;
526         else if (uv != NULL && uv->type == UC_STRING)
527                 return str->length;
528 
529         return 0;
530 }
531 
532 
533 uc_value_t *
534 ucv_int64_new(int64_t n)
535 {
536         uint64_t uval = (n < 0) ? ((n > INT64_MIN) ? (~n + 1) : INT64_MAX) : n;
537         uint64_t max = (1ULL << ((sizeof(void *) * 8) - 3)) - 1;
538         uc_integer_t *integer;
539         uintptr_t pv;
540 
541         if (uval <= max) {
542                 pv = UC_INTEGER | ((n < 0) << 2) | (uval << 3);
543 
544                 return (uc_value_t *)pv;
545         }
546 
547         integer = xalloc(sizeof(*integer));
548         integer->header.type = UC_INTEGER;
549         integer->header.refcount = 1;
550         integer->header.ext_flag = 0;
551         integer->i.s64 = n;
552 
553         return &integer->header;
554 }
555 
556 uc_value_t *
557 ucv_uint64_new(uint64_t n)
558 {
559         uint64_t max = (1ULL << ((sizeof(void *) * 8) - 3)) - 1;
560         uc_integer_t *integer;
561         uintptr_t pv;
562 
563         if (n <= max) {
564                 pv = UC_INTEGER | (n << 3);
565 
566                 return (uc_value_t *)pv;
567         }
568 
569         integer = xalloc(sizeof(*integer));
570         integer->header.type = UC_INTEGER;
571         integer->header.refcount = 1;
572         integer->header.ext_flag = 1;
573         integer->i.u64 = n;
574 
575         return &integer->header;
576 }
577 
578 uint64_t
579 ucv_uint64_get(uc_value_t *uv)
580 {
581         uintptr_t pv = (uintptr_t)uv;
582         uc_integer_t *integer;
583         double d;
584 
585         errno = 0;
586 
587         if ((pv & 3) == UC_INTEGER) {
588                 if (((pv >> 2) & 1) == 0)
589                         return (uint64_t)(pv >> 3);
590 
591                 errno = ERANGE;
592 
593                 return 0;
594         }
595 
596         switch (ucv_type(uv)) {
597         case UC_INTEGER:
598                 integer = (uc_integer_t *)uv;
599 
600                 if (integer->header.ext_flag)
601                         return integer->i.u64;
602 
603                 if (integer->i.s64 >= 0)
604                         return (uint64_t)integer->i.s64;
605 
606                 errno = ERANGE;
607 
608                 return 0;
609 
610         case UC_DOUBLE:
611                 d = ucv_double_get(uv);
612 
613                 if (d < 0.0) {
614                         errno = ERANGE;
615 
616                         return 0;
617                 }
618 
619                 if (d >= ldexp(1.0, 64)) {
620                         errno = ERANGE;
621 
622                         return UINT64_MAX;
623                 }
624 
625                 return (uint64_t)d;
626 
627         default:
628                 errno = EINVAL;
629 
630                 return 0;
631         }
632 }
633 
634 int64_t
635 ucv_int64_get(uc_value_t *uv)
636 {
637         uintptr_t pv = (uintptr_t)uv;
638         uc_integer_t *integer;
639         double d;
640 
641         errno = 0;
642 
643         if ((pv & 3) == UC_INTEGER) {
644                 if (((pv >> 2) & 1) == 0)
645                         return (int64_t)(pv >> 3);
646 
647                 return -(int64_t)(pv >> 3);
648         }
649 
650         switch (ucv_type(uv)) {
651         case UC_INTEGER:
652                 integer = (uc_integer_t *)uv;
653 
654                 if (integer->header.ext_flag && integer->i.u64 <= (uint64_t)INT64_MAX)
655                         return (int64_t)integer->i.u64;
656 
657                 if (!integer->header.ext_flag)
658                         return integer->i.s64;
659 
660                 errno = ERANGE;
661 
662                 return INT64_MAX;
663 
664         case UC_DOUBLE:
665                 d = ucv_double_get(uv);
666 
667                 if (d < ldexp(-1.0, 63)) {
668                         errno = ERANGE;
669 
670                         return INT64_MIN;
671                 }
672 
673                 if (d >= ldexp(1.0, 63)) {
674                         errno = ERANGE;
675 
676                         return INT64_MAX;
677                 }
678 
679                 return (int64_t)d;
680 
681         default:
682                 errno = EINVAL;
683 
684                 return 0;
685         }
686 }
687 
688 
689 uc_value_t *
690 ucv_double_new(double d)
691 {
692         uc_double_t *dbl;
693 
694         dbl = xalloc(sizeof(*dbl));
695         dbl->header.type = UC_DOUBLE;
696         dbl->header.refcount = 1;
697         dbl->dbl = d;
698 
699         return &dbl->header;
700 }
701 
702 double
703 ucv_double_get(uc_value_t *uv)
704 {
705         uint64_t max_int = (2ULL << (DBL_MANT_DIG - 1));
706         uc_double_t *dbl;
707         uint64_t u;
708         int64_t n;
709 
710         errno = 0;
711 
712         switch (ucv_type(uv)) {
713         case UC_DOUBLE:
714                 dbl = (uc_double_t *)uv;
715 
716                 return dbl->dbl;
717 
718         case UC_INTEGER:
719                 n = ucv_int64_get(uv);
720 
721                 if (errno == ERANGE) {
722                         u = ucv_uint64_get(uv);
723 
724                         /* signal precision loss for integral values >2^53 */
725                         if (u > max_int)
726                                 errno = ERANGE;
727 
728                         return (double)u;
729                 }
730 
731                 /* signal precision loss for integral values <-2^53 or >2^53 */
732                 if (n < -(int64_t)max_int || n > (int64_t)max_int)
733                         errno = ERANGE;
734 
735                 return (double)n;
736 
737         default:
738                 errno = EINVAL;
739 
740                 return NAN;
741         }
742 }
743 
744 
745 uc_value_t *
746 ucv_array_new(uc_vm_t *vm)
747 {
748         return ucv_array_new_length(vm, 0);
749 }
750 
751 uc_value_t *
752 ucv_array_new_length(uc_vm_t *vm, size_t length)
753 {
754         uc_array_t *array;
755 
756         array = xalloc(sizeof(*array));
757         array->header.type = UC_ARRAY;
758         array->header.refcount = 1;
759 
760         /* preallocate memory */
761         if (length)
762                 uc_vector_extend(array, length);
763 
764         if (vm) {
765                 ucv_ref(&vm->values, &array->ref);
766                 vm->alloc_refs++;
767         }
768 
769         return &array->header;
770 }
771 
772 uc_value_t *
773 ucv_array_pop(uc_value_t *uv)
774 {
775         uc_array_t *array = (uc_array_t *)uv;
776         uc_value_t *item;
777 
778         if (ucv_type(uv) != UC_ARRAY || array->count == 0)
779                 return NULL;
780 
781         item = ucv_get(array->entries[array->count - 1]);
782 
783         ucv_array_delete(uv, array->count - 1, 1);
784 
785         return item;
786 }
787 
788 uc_value_t *
789 ucv_array_push(uc_value_t *uv, uc_value_t *item)
790 {
791         uc_array_t *array = (uc_array_t *)uv;
792 
793         if (ucv_type(uv) != UC_ARRAY || uv->ext_flag)
794                 return NULL;
795 
796         ucv_array_set(uv, array->count, item);
797 
798         return item;
799 }
800 
801 uc_value_t *
802 ucv_array_shift(uc_value_t *uv)
803 {
804         uc_array_t *array = (uc_array_t *)uv;
805         uc_value_t *item;
806 
807         if (ucv_type(uv) != UC_ARRAY || array->count == 0)
808                 return NULL;
809 
810         item = ucv_get(array->entries[0]);
811 
812         ucv_array_delete(uv, 0, 1);
813 
814         return item;
815 }
816 
817 uc_value_t *
818 ucv_array_unshift(uc_value_t *uv, uc_value_t *item)
819 {
820         uc_array_t *array = (uc_array_t *)uv;
821         size_t i;
822 
823         if (ucv_type(uv) != UC_ARRAY)
824                 return NULL;
825 
826         uc_vector_extend(array, 1);
827 
828         for (i = ++array->count; i > 1; i--)
829                 array->entries[i - 1] = array->entries[i - 2];
830 
831         array->entries[0] = item;
832 
833         return item;
834 }
835 
836 typedef struct {
837         int (*cmp)(uc_value_t *, uc_value_t *, void *);
838         void *ud;
839 } array_sort_ctx_t;
840 
841 static uc_vector_sort_cb(ucv_array_sort_r_cb, uc_value_t *, array_sort_ctx_t *, {
842         return ctx->cmp(v1, v2, ctx->ud);
843 });
844 
845 void
846 ucv_array_sort_r(uc_value_t *uv,
847                  int (*cmp)(uc_value_t *, uc_value_t *, void *), void *ud)
848 {
849         array_sort_ctx_t ctx = { .cmp = cmp, .ud = ud };
850         uc_array_t *array = (uc_array_t *)uv;
851 
852         if (ucv_type(uv) != UC_ARRAY || array->count <= 1)
853                 return;
854 
855         uc_vector_sort(array, ucv_array_sort_r_cb, &ctx);
856 }
857 
858 void
859 ucv_array_sort(uc_value_t *uv, int (*cmp)(const void *, const void *))
860 {
861         uc_array_t *array = (uc_array_t *)uv;
862 
863         if (ucv_type(uv) != UC_ARRAY || array->count <= 1)
864                 return;
865 
866         qsort(array->entries, array->count, sizeof(array->entries[0]), cmp);
867 }
868 
869 bool
870 ucv_array_delete(uc_value_t *uv, size_t offset, size_t count)
871 {
872         uc_array_t *array = (uc_array_t *)uv;
873         size_t i;
874 
875         if (ucv_type(uv) != UC_ARRAY || array->count == 0)
876                 return false;
877 
878         if (offset >= array->count)
879                 return false;
880 
881         if ((offset + count) < offset)
882                 return false;
883 
884         if ((offset + count) > array->count)
885                 count = array->count - offset;
886 
887         for (i = 0; i < count; i++)
888                 ucv_put(array->entries[offset + i]);
889 
890         memmove(&array->entries[offset],
891                 &array->entries[offset + count],
892                 (array->count - (offset + count)) * sizeof(array->entries[0]));
893 
894         uc_vector_reduce(array, count);
895         array->count -= count;
896 
897         return true;
898 }
899 
900 bool
901 ucv_array_set(uc_value_t *uv, size_t index, uc_value_t *item)
902 {
903         uc_array_t *array = (uc_array_t *)uv;
904 
905         if (ucv_type(uv) != UC_ARRAY)
906                 return false;
907 
908         if (index >= array->count) {
909                 uc_vector_extend(array, index + 1 - array->count);
910                 array->count = index + 1;
911         }
912         else {
913                 ucv_put(array->entries[index]);
914         }
915 
916         array->entries[index] = item;
917 
918         return true;
919 }
920 
921 uc_value_t *
922 ucv_array_get(uc_value_t *uv, size_t index)
923 {
924         uc_array_t *array = (uc_array_t *)uv;
925 
926         if (ucv_type(uv) != UC_ARRAY)
927                 return NULL;
928 
929         if (index >= array->count)
930                 return NULL;
931 
932         return array->entries[index];
933 }
934 size_t
935 ucv_array_length(uc_value_t *uv)
936 {
937         uc_array_t *array = (uc_array_t *)uv;
938 
939         if (ucv_type(uv) != UC_ARRAY)
940                 return 0;
941 
942         return array->count;
943 }
944 
945 
946 static void
947 ucv_free_object_entry(struct lh_entry *entry)
948 {
949         uc_list_foreach(item, &uc_thread_context_get()->object_iterators) {
950                 uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
951 
952                 if (iter->u.pos == entry)
953                         iter->u.pos = entry->next;
954         }
955 
956         free(lh_entry_k(entry));
957         ucv_put(lh_entry_v(entry));
958 }
959 
960 uc_value_t *
961 ucv_object_new(uc_vm_t *vm)
962 {
963         struct lh_table *table;
964         uc_object_t *object;
965 
966         table = lh_kchar_table_new(16, ucv_free_object_entry);
967 
968         if (!table) {
969                 fprintf(stderr, "Out of memory\n");
970                 abort();
971         }
972 
973         object = xalloc(sizeof(*object));
974         object->header.type = UC_OBJECT;
975         object->header.refcount = 1;
976         object->table = table;
977 
978         if (vm) {
979                 ucv_ref(&vm->values, &object->ref);
980                 vm->alloc_refs++;
981         }
982 
983         return &object->header;
984 }
985 
986 bool
987 ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val)
988 {
989         uc_object_t *object = (uc_object_t *)uv;
990         struct lh_entry *existing_entry;
991         uc_value_t *existing_value;
992         unsigned long hash;
993         void *k;
994 
995         if (ucv_type(uv) != UC_OBJECT || uv->ext_flag)
996                 return false;
997 
998         hash = lh_get_hash(object->table, (const void *)key);
999         existing_entry = lh_table_lookup_entry_w_hash(object->table, (const void *)key, hash);
1000 
1001         if (existing_entry == NULL) {
1002                 bool rehash = (object->table->count >= object->table->size * LH_LOAD_FACTOR);
1003 
1004                 /* insert will rehash table, backup affected iterator states */
1005                 if (rehash) {
1006                         uc_list_foreach(item, &uc_thread_context_get()->object_iterators) {
1007                                 uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
1008 
1009                                 if (iter->table != object->table)
1010                                         continue;
1011 
1012                                 if (iter->u.pos == NULL)
1013                                         continue;
1014 
1015                                 iter->u.kh.k = iter->u.pos->k;
1016                                 iter->u.kh.hash = lh_get_hash(iter->table, iter->u.kh.k);
1017                         }
1018                 }
1019 
1020                 k = xstrdup(key);
1021 
1022                 if (lh_table_insert_w_hash(object->table, k, val, hash, 0) != 0) {
1023                         free(k);
1024 
1025                         return false;
1026                 }
1027 
1028                 /* restore affected iterator state pointer after rehash */
1029                 if (rehash) {
1030                         uc_list_foreach(item, &uc_thread_context_get()->object_iterators) {
1031                                 uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
1032 
1033                                 if (iter->table != object->table)
1034                                         continue;
1035 
1036                                 if (iter->u.kh.k == NULL)
1037                                         continue;
1038 
1039                                 iter->u.pos = lh_table_lookup_entry_w_hash(iter->table,
1040                                                                            iter->u.kh.k,
1041                                                                            iter->u.kh.hash);
1042                         }
1043                 }
1044 
1045                 return true;
1046         }
1047 
1048         existing_value = (uc_value_t *)lh_entry_v(existing_entry);
1049 
1050         if (existing_value)
1051                 ucv_put(existing_value);
1052 
1053         existing_entry->v = val;
1054 
1055         return true;
1056 }
1057 
1058 
1059 typedef struct {
1060         int (*cmp)(const void *, const void *);
1061         int (*cmpr)(const char *, uc_value_t *, const char *, uc_value_t *, void *);
1062         void *ud;
1063 } object_sort_ctx_t;
1064 
1065 static uc_vector_sort_cb(ucv_object_sort_cb, const void *, object_sort_ctx_t *, {
1066         (void)v1;
1067         (void)v2;
1068 
1069         return ctx->cmp(k1, k2);
1070 });
1071 
1072 static uc_vector_sort_cb(ucv_object_sort_r_cb, const struct lh_entry *, object_sort_ctx_t *, {
1073         return ctx->cmpr(
1074                 v1 ? lh_entry_k(v1) : NULL, v1 ? lh_entry_v(v1) : NULL,
1075                 v2 ? lh_entry_k(v2) : NULL, v2 ? lh_entry_v(v2) : NULL,
1076                 ctx->ud);
1077 });
1078 
1079 static void
1080 ucv_object_sort_common(uc_value_t *uv, object_sort_ctx_t *ctx)
1081 {
1082         uc_object_t *object = (uc_object_t *)uv;
1083         struct lh_table *t;
1084         struct lh_entry *e;
1085         size_t i;
1086 
1087         struct {
1088                 struct lh_entry **entries;
1089                 size_t count;
1090         } keys = { 0 };
1091 
1092         if (ucv_type(uv) != UC_OBJECT || lh_table_length(object->table) <= 1)
1093                 return;
1094 
1095         for (t = object->table, e = t->head; e; e = e->next)
1096                 uc_vector_push(&keys, e);
1097 
1098         if (!keys.entries)
1099                 return;
1100 
1101         uc_vector_sort(&keys,
1102                 ctx->cmpr ? ucv_object_sort_r_cb : ucv_object_sort_cb, ctx);
1103 
1104         for (i = 0; i < keys.count; i++) {
1105                 e = keys.entries[i];
1106 
1107                 if (i == 0) {
1108                         t->head = t->tail = e;
1109                         e->next = e->prev = NULL;
1110                 }
1111                 else {
1112                         t->tail->next = e;
1113                         e->prev = t->tail;
1114                         e->next = NULL;
1115                         t->tail = e;
1116                 }
1117         }
1118 
1119         uc_vector_clear(&keys);
1120 }
1121 
1122 void
1123 ucv_object_sort_r(uc_value_t *uv,
1124                   int (*cmp)(const char *, uc_value_t *,
1125                              const char *, uc_value_t *, void *),
1126                   void *ud)
1127 {
1128         object_sort_ctx_t ctx = { .cmp = NULL, .cmpr = cmp, .ud = ud };
1129 
1130         ucv_object_sort_common(uv, &ctx);
1131 }
1132 
1133 void
1134 ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *))
1135 {
1136         object_sort_ctx_t ctx = { .cmp = cmp, .cmpr = NULL, .ud = NULL };
1137 
1138         ucv_object_sort_common(uv, &ctx);
1139 }
1140 
1141 bool
1142 ucv_object_delete(uc_value_t *uv, const char *key)
1143 {
1144         uc_object_t *object = (uc_object_t *)uv;
1145 
1146         if (ucv_type(uv) != UC_OBJECT || uv->ext_flag)
1147                 return false;
1148 
1149         return (lh_table_delete(object->table, key) == 0);
1150 }
1151 
1152 uc_value_t *
1153 ucv_object_get(uc_value_t *uv, const char *key, bool *found)
1154 {
1155         uc_object_t *object = (uc_object_t *)uv;
1156         uc_value_t *val = NULL;
1157         bool rv;
1158 
1159         if (found != NULL)
1160                 *found = false;
1161 
1162         if (ucv_type(uv) != UC_OBJECT)
1163                 return NULL;
1164 
1165         rv = lh_table_lookup_ex(object->table, (const void *)key, (void **)&val);
1166 
1167         if (found != NULL)
1168                 *found = rv;
1169 
1170         return val;
1171 }
1172 
1173 size_t
1174 ucv_object_length(uc_value_t *uv)
1175 {
1176         uc_object_t *object = (uc_object_t *)uv;
1177 
1178         if (ucv_type(uv) != UC_OBJECT)
1179                 return 0;
1180 
1181         return lh_table_length(object->table);
1182 }
1183 
1184 
1185 uc_value_t *
1186 ucv_cfunction_new(const char *name, uc_cfn_ptr_t fptr)
1187 {
1188         uc_cfunction_t *cfn;
1189         size_t namelen = 0;
1190 
1191         if (name)
1192                 namelen = strlen(name);
1193 
1194         cfn = xalloc(sizeof(*cfn) + namelen + 1);
1195         cfn->header.type = UC_CFUNCTION;
1196         cfn->header.refcount = 1;
1197 
1198         if (name)
1199                 strcpy(cfn->name, name);
1200 
1201         cfn->cfn = fptr;
1202 
1203         return &cfn->header;
1204 }
1205 
1206 
1207 uc_value_t *
1208 ucv_closure_new(uc_vm_t *vm, uc_function_t *function, bool arrow_fn)
1209 {
1210         uc_closure_t *closure;
1211 
1212         closure = xalloc(sizeof(*closure) + (sizeof(uc_upvalref_t *) * function->nupvals));
1213         closure->header.type = UC_CLOSURE;
1214         closure->header.refcount = 1;
1215         closure->function = function;
1216         closure->is_arrow = arrow_fn;
1217         closure->upvals = function->nupvals ? (uc_upvalref_t **)((uintptr_t)closure + ALIGN(sizeof(*closure))) : NULL;
1218 
1219         if (vm) {
1220                 ucv_ref(&vm->values, &closure->ref);
1221                 vm->alloc_refs++;
1222         }
1223 
1224         uc_program_get(function->program);
1225 
1226         return &closure->header;
1227 }
1228 
1229 
1230 uc_resource_type_t *
1231 ucv_resource_type_add(uc_vm_t *vm, const char *name, uc_value_t *proto, void (*freefn)(void *))
1232 {
1233         uc_resource_type_t *type;
1234 
1235         type = ucv_resource_type_lookup(vm, name);
1236 
1237         if (type) {
1238                 ucv_put(proto);
1239 
1240                 return type;
1241         }
1242 
1243         type = xalloc(sizeof(*type));
1244         type->name = name;
1245         type->proto = proto;
1246         type->free = freefn;
1247 
1248         uc_vector_push(&vm->restypes, type);
1249 
1250         return type;
1251 }
1252 
1253 uc_resource_type_t *
1254 ucv_resource_type_lookup(uc_vm_t *vm, const char *name)
1255 {
1256         size_t i;
1257 
1258         for (i = 0; i < vm->restypes.count; i++)
1259                 if (!strcmp(vm->restypes.entries[i]->name, name))
1260                         return vm->restypes.entries[i];
1261 
1262         return NULL;
1263 }
1264 
1265 
1266 uc_value_t *
1267 ucv_resource_new(uc_resource_type_t *type, void *data)
1268 {
1269         uc_resource_t *res;
1270 
1271         res = xalloc(sizeof(*res));
1272         res->header.type = UC_RESOURCE;
1273         res->header.refcount = 1;
1274         res->type = type;
1275         res->data = data;
1276 
1277         return &res->header;
1278 }
1279 
1280 uc_value_t *
1281 ucv_resource_new_ex(uc_vm_t *vm, uc_resource_type_t *type, void **data, size_t uvcount, size_t datasize)
1282 {
1283         uc_resource_ext_t *res;
1284         size_t size;
1285 
1286         assert(uvcount < (1 << 8));
1287         assert(datasize < (8 << 20));
1288 
1289         size = sizeof(*res);
1290         size += uvcount * sizeof(uc_value_t *);
1291         size += datasize = (datasize + 7) & ~7;
1292 
1293         res = xalloc(size);
1294         res->header.type = UC_RESOURCE;
1295         res->header.refcount = 1;
1296         res->header.ext_flag = 1;
1297         res->type = type;
1298         res->uvcount = uvcount;
1299         res->datasize = datasize / 8;
1300         if (data)
1301                 *data = res + 1;
1302 
1303         if (vm && uvcount) {
1304                 ucv_ref_tail(&vm->values, &res->ref);
1305                 vm->alloc_refs++;
1306         }
1307 
1308         return &res->header;
1309 }
1310 
1311 static bool
1312 ucv_resource_check(uc_value_t *uv, const char *name)
1313 {
1314         uc_resource_type_t *restype;
1315 
1316         if (ucv_type(uv) != UC_RESOURCE)
1317                 return false;
1318 
1319         if (!name)
1320                 return true;
1321 
1322         restype = ucv_resource_type(uv);
1323 
1324         return restype && !strcmp(restype->name, name);
1325 }
1326 
1327 void *
1328 ucv_resource_data(uc_value_t *uv, const char *name)
1329 {
1330         if (!ucv_resource_check(uv, name))
1331                 return NULL;
1332 
1333         if (uv->ext_flag) {
1334                 uc_resource_ext_t *res = (uc_resource_ext_t *)uv;
1335 
1336                 return res + 1;
1337         }
1338         else {
1339                 uc_resource_t *res = (uc_resource_t *)uv;
1340 
1341                 return res->data;
1342         }
1343 }
1344 
1345 void **
1346 ucv_resource_dataptr(uc_value_t *uv, const char *name)
1347 {
1348         uc_resource_t *res = (uc_resource_t *)uv;
1349 
1350         if (!ucv_resource_check(uv, name) || res->header.ext_flag)
1351                 return NULL;
1352 
1353         return &res->data;
1354 }
1355 
1356 uc_value_t *
1357 ucv_resource_value_get(uc_value_t *uv, size_t idx)
1358 {
1359         uc_resource_ext_t *res = (uc_resource_ext_t *)uv;
1360         uc_value_t **uvdata = ucv_resource_values(res);
1361 
1362         if (!uvdata || idx >= res->uvcount)
1363                 return NULL;
1364 
1365         return uvdata[idx];
1366 }
1367 
1368 bool
1369 ucv_resource_value_set(uc_value_t *uv, size_t idx, uc_value_t *val)
1370 {
1371         uc_resource_ext_t *res = (uc_resource_ext_t *)uv;
1372         uc_value_t **uvdata = ucv_resource_values(res);
1373 
1374         if (!uvdata || idx >= res->uvcount)
1375                 return NULL;
1376 
1377         ucv_put(uvdata[idx]);
1378         uvdata[idx] = val;
1379 
1380         return true;
1381 }
1382 
1383 uc_value_t *
1384 ucv_regexp_new(const char *pattern, bool icase, bool newline, bool global, char **error)
1385 {
1386         int cflags = REG_EXTENDED, res;
1387         uc_regexp_t *re;
1388         size_t len;
1389 
1390         re = xalloc(sizeof(*re) + strlen(pattern) + 1);
1391         re->header.type = UC_REGEXP;
1392         re->header.refcount = 1;
1393         re->icase = icase;
1394         re->global = global;
1395         re->newline = newline;
1396         strcpy(re->source, pattern);
1397 
1398         if (icase)
1399                 cflags |= REG_ICASE;
1400 
1401         if (newline)
1402                 cflags |= REG_NEWLINE;
1403 
1404         res = regcomp(&re->regexp, pattern, cflags);
1405 
1406         if (res != 0) {
1407                 if (error) {
1408                         len = regerror(res, &re->regexp, NULL, 0);
1409                         *error = xalloc(len);
1410 
1411                         regerror(res, &re->regexp, *error, len);
1412                 }
1413 
1414                 free(re);
1415 
1416                 return NULL;
1417         }
1418 
1419         return &re->header;
1420 }
1421 
1422 
1423 uc_value_t *
1424 ucv_upvalref_new(size_t slot)
1425 {
1426         uc_upvalref_t *up;
1427 
1428         up = xalloc(sizeof(*up));
1429         up->header.type = UC_UPVALUE;
1430         up->header.refcount = 1;
1431         up->slot = slot;
1432 
1433         return &up->header;
1434 }
1435 
1436 
1437 uc_value_t *
1438 ucv_prototype_get(uc_value_t *uv)
1439 {
1440         uc_resource_type_t *restype;
1441         uc_object_t *object;
1442         uc_array_t *array;
1443 
1444         switch (ucv_type(uv)) {
1445         case UC_ARRAY:
1446                 array = (uc_array_t *)uv;
1447 
1448                 return array->proto;
1449 
1450         case UC_OBJECT:
1451                 object = (uc_object_t *)uv;
1452 
1453                 return object->proto;
1454 
1455         case UC_RESOURCE:
1456                 restype = ucv_resource_type(uv);
1457 
1458                 return restype ? restype->proto : NULL;
1459 
1460         default:
1461                 return NULL;
1462         }
1463 }
1464 
1465 bool
1466 ucv_prototype_set(uc_value_t *uv, uc_value_t *proto)
1467 {
1468         uc_object_t *object;
1469         uc_array_t *array;
1470 
1471         if (ucv_type(proto) != UC_OBJECT)
1472                 return false;
1473 
1474         switch (ucv_type(uv)) {
1475         case UC_ARRAY:
1476                 array = (uc_array_t *)uv;
1477                 array->proto = proto;
1478 
1479                 return true;
1480 
1481         case UC_OBJECT:
1482                 object = (uc_object_t *)uv;
1483                 object->proto = proto;
1484 
1485                 return true;
1486 
1487         default:
1488                 return false;
1489         }
1490 }
1491 
1492 uc_value_t *
1493 ucv_property_get(uc_value_t *uv, const char *key)
1494 {
1495         uc_value_t *val;
1496         bool found;
1497 
1498         for (; uv; uv = ucv_prototype_get(uv)) {
1499                 val = ucv_object_get(uv, key, &found);
1500 
1501                 if (found)
1502                         return val;
1503         }
1504 
1505         return NULL;
1506 }
1507 
1508 
1509 uc_value_t *
1510 ucv_from_json(uc_vm_t *vm, json_object *jso)
1511 {
1512         //uc_array_t *arr;
1513         uc_value_t *uv, *item;
1514         int64_t n;
1515         size_t i;
1516 
1517         switch (json_object_get_type(jso)) {
1518         case json_type_null:
1519                 return NULL;
1520 
1521         case json_type_boolean:
1522                 return ucv_boolean_new(json_object_get_boolean(jso));
1523 
1524         case json_type_double:
1525                 return ucv_double_new(json_object_get_double(jso));
1526 
1527         case json_type_int:
1528                 n = json_object_get_int64(jso);
1529 
1530                 if (n == INT64_MAX)
1531                         return ucv_uint64_new(json_object_get_uint64(jso));
1532 
1533                 return ucv_int64_new(n);
1534 
1535         case json_type_object:
1536                 uv = ucv_object_new(vm);
1537 
1538                 json_object_object_foreach(jso, key, val) {
1539                         item = ucv_from_json(vm, val);
1540 
1541                         if (!ucv_object_add(uv, key, item))
1542                                 ucv_put(item);
1543 
1544 #ifdef __clang_analyzer__
1545                         /* Clang static analyzer does not understand that the object retains
1546                          * our item so pretend to free it here to suppress the false positive
1547                          * memory leak warning. */
1548                         ucv_put(item);
1549 #endif
1550                 }
1551 
1552                 return uv;
1553 
1554         case json_type_array:
1555                 /* XXX
1556                 arr = (uc_array_t *)ucv_array_new_length(vm, json_object_array_length(jso));
1557 
1558                 for (i = 0; i < arr->count; i++)
1559                         arr->entries[i] = ucv_from_json(vm, json_object_array_get_idx(jso, i));
1560 
1561                 return &arr->header;
1562                 */
1563                 uv = ucv_array_new(vm);
1564 
1565                 for (i = 0; i < json_object_array_length(jso); i++) {
1566                         item = ucv_from_json(vm, json_object_array_get_idx(jso, i));
1567 
1568                         if (!ucv_array_push(uv, item))
1569                                 ucv_put(item);
1570 
1571 #ifdef __clang_analyzer__
1572                         /* Clang static analyzer does not understand that the array retains
1573                          * our item so pretend to free it here to suppress the false positive
1574                          * memory leak warning. */
1575                         ucv_put(item);
1576 #endif
1577                 }
1578 
1579                 return uv;
1580 
1581         case json_type_string:
1582                 return ucv_string_new_length(json_object_get_string(jso), json_object_get_string_len(jso));
1583         }
1584 
1585         return NULL;
1586 }
1587 
1588 json_object *
1589 ucv_to_json(uc_value_t *uv)
1590 {
1591         uc_regexp_t *regexp;
1592         uc_array_t *array;
1593         json_object *jso;
1594         size_t i;
1595         char *s;
1596 
1597         switch (ucv_type(uv)) {
1598         case UC_BOOLEAN:
1599                 return json_object_new_boolean(ucv_boolean_get(uv));
1600 
1601         case UC_INTEGER:
1602                 if (ucv_is_u64(uv))
1603                         return json_object_new_uint64(ucv_uint64_get(uv));
1604 
1605                 return json_object_new_int64(ucv_int64_get(uv));
1606 
1607         case UC_DOUBLE:
1608                 return json_object_new_double(ucv_double_get(uv));
1609 
1610         case UC_STRING:
1611                 return json_object_new_string_len(ucv_string_get(uv), ucv_string_length(uv));
1612 
1613         case UC_ARRAY:
1614                 array = (uc_array_t *)uv;
1615                 jso = json_object_new_array_ext(array->count);
1616 
1617                 for (i = 0; i < array->count; i++)
1618                         json_object_array_put_idx(jso, i, ucv_to_json(array->entries[i]));
1619 
1620                 return jso;
1621 
1622         case UC_OBJECT:
1623                 jso = json_object_new_object();
1624 
1625                 ucv_object_foreach(uv, key, val)
1626                         json_object_object_add(jso, key, ucv_to_json(val));
1627 
1628                 return jso;
1629 
1630         case UC_REGEXP:
1631                 regexp = (uc_regexp_t *)uv;
1632                 i = asprintf(&s, "/%s/%s%s%s",
1633                         regexp->source,
1634                         regexp->global ? "g" : "",
1635                         regexp->icase ? "i" : "",
1636                         regexp->newline ? "s" : "");
1637 
1638                 if (i <= 0)
1639                         return NULL;
1640 
1641                 jso = json_object_new_string_len(s, i);
1642 
1643                 free(s);
1644 
1645                 return jso;
1646 
1647         case UC_CLOSURE:
1648         case UC_CFUNCTION:
1649         case UC_RESOURCE:
1650         case UC_UPVALUE:
1651         case UC_PROGRAM:
1652         case UC_SOURCE:
1653         case UC_NULL:
1654                 return NULL;
1655         }
1656 
1657         return NULL;
1658 }
1659 
1660 static void
1661 ucv_to_string_json_encoded(uc_stringbuf_t *pb, const char *s, size_t len, bool regexp)
1662 {
1663         size_t i;
1664 
1665         if (!regexp)
1666                 ucv_stringbuf_append(pb, "\"");
1667 
1668         for (i = 0; s != NULL && i < len; i++, s++) {
1669                 switch (*s) {
1670                 case '"':
1671                         ucv_stringbuf_append(pb, "\\\"");
1672                         break;
1673 
1674                 case '\\':
1675                         ucv_stringbuf_append(pb, "\\\\");
1676                         break;
1677 
1678                 case '\b':
1679                         ucv_stringbuf_append(pb, "\\b");
1680                         break;
1681 
1682                 case '\f':
1683                         ucv_stringbuf_append(pb, "\\f");
1684                         break;
1685 
1686                 case '\n':
1687                         ucv_stringbuf_append(pb, "\\n");
1688                         break;
1689 
1690                 case '\r':
1691                         ucv_stringbuf_append(pb, "\\r");
1692                         break;
1693 
1694                 case '\t':
1695                         ucv_stringbuf_append(pb, "\\t");
1696                         break;
1697 
1698                 case '/':
1699                         ucv_stringbuf_append(pb, "/");
1700                         break;
1701 
1702                 default:
1703                         if ((unsigned char)*s < 0x20)
1704                                 ucv_stringbuf_printf(pb, "\\u%04x", (unsigned char)*s);
1705                         else
1706                                 ucv_stringbuf_addstr(pb, s, 1);
1707 
1708                         break;
1709                 }
1710         }
1711 
1712         if (!regexp)
1713                 ucv_stringbuf_append(pb, "\"");
1714 }
1715 
1716 static bool
1717 ucv_call_tostring(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json)
1718 {
1719         uc_value_t *proto = ucv_prototype_get(uv);
1720         uc_value_t *tostr = ucv_object_get(proto, "tostring", NULL);
1721         uc_value_t *str;
1722         size_t l;
1723         char *s;
1724 
1725         if (!ucv_is_callable(tostr))
1726                 return false;
1727 
1728         uc_vm_stack_push(vm, ucv_get(uv));
1729         uc_vm_stack_push(vm, ucv_get(tostr));
1730 
1731         if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE)
1732                 return false;
1733 
1734         str = uc_vm_stack_pop(vm);
1735 
1736         if (ucv_type(str) == UC_STRING) {
1737                 s = ucv_string_get(str);
1738                 l = ucv_string_length(str);
1739 
1740                 if (json)
1741                         ucv_to_string_json_encoded(pb, s, l, false);
1742                 else if (s)
1743                         ucv_stringbuf_addstr(pb, s, l);
1744         }
1745         else if (json) {
1746                 ucv_stringbuf_append(pb, "\"\"");
1747         }
1748 
1749         ucv_put(str);
1750 
1751         return true;
1752 }
1753 
1754 void
1755 _ucv_stringbuf_append(uc_stringbuf_t *pb, const char *str, size_t len)
1756 {
1757         printbuf_memappend_fast(pb, str, (int)len);
1758 }
1759 
1760 static void
1761 ucv_to_stringbuf_add_padding(uc_stringbuf_t *pb, char pad_char, size_t pad_size)
1762 {
1763         if (pad_char != '\0' && pad_char != '\1') {
1764                 ucv_stringbuf_append(pb, "\n");
1765                 printbuf_memset(pb, -1, pad_char, pad_size);
1766         }
1767         else {
1768                 ucv_stringbuf_append(pb, " ");
1769         }
1770 }
1771 
1772 static void
1773 ucv_to_stringbuf_add_double(uc_stringbuf_t *pb, double val, bool json)
1774 {
1775         int len = ucv_stringbuf_printf(pb, "%.14g", val);
1776 
1777         if (!json)
1778                 return;
1779 
1780         for (char *p = pb->buf + pb->bpos - len; len > 0; len--, p++)
1781                 if (*p == '.' || *p == 'e')
1782                         return;
1783 
1784         ucv_stringbuf_append(pb, ".0");
1785 }
1786 
1787 void
1788 ucv_to_stringbuf_formatted(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, size_t depth, char pad_char, size_t pad_size)
1789 {
1790         bool json = (pad_char != '\0');
1791         uc_resource_type_t *restype;
1792         uc_cfunction_t *cfunction;
1793         uc_function_t *function;
1794         uc_closure_t *closure;
1795         uc_regexp_t *regexp;
1796         uc_value_t *argname;
1797         uc_upvalref_t *ref;
1798         uc_array_t *array;
1799         size_t i, l;
1800         double d;
1801         char *s;
1802 
1803         if (ucv_is_marked(uv)) {
1804                 ucv_stringbuf_append(pb, "null");
1805 
1806                 return;
1807         }
1808 
1809         if (vm != NULL && ucv_call_tostring(vm, pb, uv, json))
1810                 return;
1811 
1812         ucv_set_mark(uv);
1813 
1814         switch (ucv_type(uv)) {
1815         case UC_NULL:
1816                 ucv_stringbuf_append(pb, "null");
1817                 break;
1818 
1819         case UC_BOOLEAN:
1820                 if (ucv_boolean_get(uv))
1821                         ucv_stringbuf_append(pb, "true");
1822                 else
1823                         ucv_stringbuf_append(pb, "false");
1824                 break;
1825 
1826         case UC_INTEGER:
1827                 if (ucv_is_u64(uv))
1828                         ucv_stringbuf_printf(pb, "%" PRIu64, ucv_uint64_get(uv));
1829                 else
1830                         ucv_stringbuf_printf(pb, "%" PRId64, ucv_int64_get(uv));
1831                 break;
1832 
1833         case UC_DOUBLE:
1834                 d = ucv_double_get(uv);
1835 
1836                 if (json && isnan(d))
1837                         ucv_stringbuf_append(pb, "\"NaN\"");
1838                 else if (json && d == INFINITY)
1839                         ucv_stringbuf_append(pb, "1e309");
1840                 else if (json && d == -INFINITY)
1841                         ucv_stringbuf_append(pb, "-1e309");
1842                 else if (isnan(d))
1843                         ucv_stringbuf_append(pb, "NaN");
1844                 else if (d == INFINITY)
1845                         ucv_stringbuf_append(pb, "Infinity");
1846                 else if (d == -INFINITY)
1847                         ucv_stringbuf_append(pb, "-Infinity");
1848                 else
1849                         ucv_to_stringbuf_add_double(pb, d, json);
1850 
1851                 break;
1852 
1853         case UC_STRING:
1854                 s = ucv_string_get(uv);
1855                 l = ucv_string_length(uv);
1856 
1857                 if (s) {
1858                         if (json)
1859                                 ucv_to_string_json_encoded(pb, s, l, false);
1860                         else
1861                                 ucv_stringbuf_addstr(pb, s, l);
1862                 }
1863 
1864                 break;
1865 
1866         case UC_ARRAY:
1867                 array = (uc_array_t *)uv;
1868 
1869                 ucv_stringbuf_append(pb, "[");
1870 
1871                 for (i = 0; i < array->count; i++) {
1872                         if (i)
1873                                 ucv_stringbuf_append(pb, ",");
1874 
1875                         ucv_to_stringbuf_add_padding(pb, pad_char, (depth + 1) * pad_size);
1876                         ucv_to_stringbuf_formatted(vm, pb, array->entries[i], depth + 1, pad_char ? pad_char : '\1', pad_size);
1877                 }
1878 
1879                 ucv_to_stringbuf_add_padding(pb, pad_char, depth * pad_size);
1880                 ucv_stringbuf_append(pb, "]");
1881                 break;
1882 
1883         case UC_OBJECT:
1884                 ucv_stringbuf_append(pb, "{");
1885 
1886                 i = 0;
1887                 ucv_object_foreach(uv, key, val) {
1888                         if (i++)
1889                                 ucv_stringbuf_append(pb, ",");
1890 
1891                         ucv_to_stringbuf_add_padding(pb, pad_char, (depth + 1) * pad_size);
1892                         ucv_to_string_json_encoded(pb, key, strlen(key), false);
1893                         ucv_stringbuf_append(pb, ": ");
1894                         ucv_to_stringbuf_formatted(vm, pb, val, depth + 1, pad_char ? pad_char : '\1', pad_size);
1895                 }
1896 
1897                 ucv_to_stringbuf_add_padding(pb, pad_char, depth * pad_size);
1898                 ucv_stringbuf_append(pb, "}");
1899                 break;
1900 
1901         case UC_REGEXP:
1902                 regexp = (uc_regexp_t *)uv;
1903 
1904                 if (json)
1905                         ucv_stringbuf_append(pb, "\"");
1906 
1907                 ucv_stringbuf_append(pb, "/");
1908                 ucv_to_string_json_encoded(pb, regexp->source, strlen(regexp->source), true);
1909                 ucv_stringbuf_append(pb, "/");
1910 
1911                 if (regexp->global)
1912                         ucv_stringbuf_append(pb, "g");
1913 
1914                 if (regexp->icase)
1915                         ucv_stringbuf_append(pb, "i");
1916 
1917                 if (regexp->newline)
1918                         ucv_stringbuf_append(pb, "s");
1919 
1920                 if (json)
1921                         ucv_stringbuf_append(pb, "\"");
1922 
1923                 break;
1924 
1925         case UC_CLOSURE:
1926                 closure = (uc_closure_t *)uv;
1927                 function = closure->function;
1928 
1929                 if (json)
1930                         ucv_stringbuf_append(pb, "\"");
1931 
1932                 if (!closure->is_arrow) {
1933                         ucv_stringbuf_append(pb, "function");
1934 
1935                         if (function->name[0]) {
1936                                 ucv_stringbuf_append(pb, " ");
1937                                 ucv_stringbuf_addstr(pb, function->name, strlen(function->name));
1938                         }
1939                 }
1940 
1941                 ucv_stringbuf_append(pb, "(");
1942 
1943                 for (i = 1; i <= function->nargs; i++) {
1944                         argname = uc_chunk_debug_get_variable(&function->chunk, i - 1, i, false);
1945 
1946                         if (i > 1)
1947                                 ucv_stringbuf_append(pb, ", ");
1948 
1949                         if (i == function->nargs && function->vararg)
1950                                 ucv_stringbuf_append(pb, "...");
1951 
1952                         if (argname) {
1953                                 s = ucv_string_get(argname);
1954                                 l = ucv_string_length(argname);
1955 
1956                                 if (s)
1957                                         ucv_stringbuf_addstr(pb, s, l);
1958 
1959                                 ucv_put(argname);
1960 
1961                                 continue;
1962                         }
1963 
1964                         ucv_stringbuf_printf(pb, "[arg%zu]", i);
1965                 }
1966 
1967                 ucv_stringbuf_printf(pb, ")%s { ... }%s",
1968                         closure->is_arrow ? " =>" : "",
1969                         json ? "\"" : "");
1970 
1971                 break;
1972 
1973         case UC_CFUNCTION:
1974                 cfunction = (uc_cfunction_t *)uv;
1975 
1976                 ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s",
1977                         json ? "\"" : "",
1978                         cfunction->name[0] ? " " : "",
1979                         cfunction->name[0] ? cfunction->name : "",
1980                         json ? "\"" : "");
1981 
1982                 break;
1983 
1984         case UC_RESOURCE:
1985                 restype = ucv_resource_type(uv);
1986 
1987                 ucv_stringbuf_printf(pb, "%s<%s %p>%s",
1988                         json ? "\"" : "",
1989                         restype ? restype->name : "resource",
1990                         ucv_resource_data(uv, NULL),
1991                         json ? "\"" : "");
1992 
1993                 break;
1994 
1995         case UC_UPVALUE:
1996                 ref = (uc_upvalref_t *)uv;
1997 
1998                 if (ref->closed)
1999                         ucv_to_stringbuf_formatted(vm, pb, ref->value, depth, pad_char, pad_size);
2000                 else if (vm != NULL && ref->slot < vm->stack.count)
2001                         ucv_to_stringbuf_formatted(vm, pb, vm->stack.entries[ref->slot], depth, pad_char, pad_size);
2002                 else
2003                         ucv_stringbuf_printf(pb, "%s<upvalref %p>%s",
2004                                 json ? "\"" : "",
2005                                 uv,
2006                                 json ? "\"" : "");
2007 
2008                 break;
2009 
2010         case UC_PROGRAM:
2011                 ucv_stringbuf_printf(pb, "%s<program %p>%s",
2012                         json ? "\"" : "",
2013                         uv,
2014                         json ? "\"" : "");
2015 
2016                 break;
2017 
2018         case UC_SOURCE:
2019                 ucv_stringbuf_printf(pb, "%s<source %p>%s",
2020                         json ? "\"" : "",
2021                         uv,
2022                         json ? "\"" : "");
2023         }
2024 
2025         ucv_clear_mark(uv);
2026 }
2027 
2028 static char *
2029 ucv_to_string_any(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t pad_size)
2030 {
2031         uc_stringbuf_t *pb = xprintbuf_new();
2032         char *rv;
2033 
2034         ucv_to_stringbuf_formatted(vm, pb, uv, 0, pad_char, pad_size);
2035 
2036         rv = pb->buf;
2037 
2038         free(pb);
2039 
2040         return rv;
2041 }
2042 
2043 char *
2044 ucv_to_string(uc_vm_t *vm, uc_value_t *uv)
2045 {
2046         return ucv_to_string_any(vm, uv, '\0', 0);
2047 }
2048 
2049 char *
2050 ucv_to_jsonstring_formatted(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t pad_size)
2051 {
2052         return ucv_to_string_any(vm, uv, pad_char ? pad_char : '\1', pad_size);
2053 }
2054 
2055 
2056 bool
2057 ucv_is_equal(uc_value_t *uv1, uc_value_t *uv2)
2058 {
2059         uc_type_t t1 = ucv_type(uv1);
2060         uc_type_t t2 = ucv_type(uv2);
2061         const char *s1, *s2;
2062         uint64_t u1, u2;
2063         int64_t n1, n2;
2064         bool b1, b2;
2065 
2066         if (t1 != t2)
2067                 return false;
2068 
2069         if (t1 != UC_DOUBLE && uv1 == uv2)
2070                 return true;
2071 
2072         switch (t1) {
2073         case UC_NULL:
2074                 return true;
2075 
2076         case UC_BOOLEAN:
2077                 return ucv_boolean_get(uv1) == ucv_boolean_get(uv2);
2078 
2079         case UC_DOUBLE:
2080                 return ucv_double_get(uv1) == ucv_double_get(uv2);
2081 
2082         case UC_INTEGER:
2083                 n1 = ucv_int64_get(uv1);
2084                 b1 = (errno == 0);
2085 
2086                 n2 = ucv_int64_get(uv2);
2087                 b2 = (errno == 0);
2088 
2089                 if (b1 && b2)
2090                         return (n1 == n2);
2091 
2092                 u1 = ucv_uint64_get(uv1);
2093                 b1 = (errno == 0);
2094 
2095                 u2 = ucv_uint64_get(uv2);
2096                 b2 = (errno == 0);
2097 
2098                 if (b1 && b2)
2099                         return (u1 == u2);
2100 
2101                 return false;
2102 
2103         case UC_STRING:
2104                 s1 = ucv_string_get(uv1);
2105                 s2 = ucv_string_get(uv2);
2106                 u1 = ucv_string_length(uv1);
2107                 u2 = ucv_string_length(uv2);
2108 
2109                 if (s1 == NULL || s2 == NULL || u1 != u2)
2110                         return false;
2111 
2112                 return (memcmp(s1, s2, u1) == 0);
2113 
2114         case UC_ARRAY:
2115                 u1 = ucv_array_length(uv1);
2116                 u2 = ucv_array_length(uv2);
2117 
2118                 if (u1 != u2)
2119                         return false;
2120 
2121                 for (u1 = 0; u1 < u2; u1++)
2122                         if (!ucv_is_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1)))
2123                                 return false;
2124 
2125                 return true;
2126 
2127         case UC_OBJECT:
2128                 u1 = ucv_object_length(uv1);
2129                 u2 = ucv_object_length(uv2);
2130 
2131                 if (u1 != u2)
2132                         return false;
2133 
2134                 ucv_object_foreach(uv1, key, val) {
2135                         if (!ucv_is_equal(val, ucv_object_get(uv2, key, NULL)))
2136                                 return false;
2137                 }
2138 
2139                 ucv_object_foreach(uv2, key2, val2) {
2140                         (void)val2;
2141                         ucv_object_get(uv1, key2, &b1);
2142 
2143                         if (!b1)
2144                                 return false;
2145                 }
2146 
2147                 return true;
2148 
2149         default:
2150                 return false;
2151         }
2152 }
2153 
2154 bool
2155 ucv_is_truish(uc_value_t *val)
2156 {
2157         double d;
2158 
2159         switch (ucv_type(val)) {
2160         case UC_INTEGER:
2161                 if (ucv_is_u64(val))
2162                         return (ucv_uint64_get(val) != 0);
2163 
2164                 return (ucv_int64_get(val) != 0);
2165 
2166         case UC_DOUBLE:
2167                 d = ucv_double_get(val);
2168 
2169                 return (d != 0 && !isnan(d));
2170 
2171         case UC_BOOLEAN:
2172                 return ucv_boolean_get(val);
2173 
2174         case UC_STRING:
2175                 return (ucv_string_length(val) > 0);
2176 
2177         case UC_NULL:
2178                 return false;
2179 
2180         default:
2181                 return true;
2182         }
2183 }
2184 
2185 uc_value_t *
2186 ucv_to_number(uc_value_t *v)
2187 {
2188         switch (ucv_type(v)) {
2189         case UC_NULL:
2190                 return ucv_uint64_new(0);
2191 
2192         case UC_BOOLEAN:
2193                 return ucv_uint64_new(ucv_boolean_get(v));
2194 
2195         case UC_INTEGER:
2196                 return ucv_get(v);
2197 
2198         case UC_DOUBLE:
2199                 if (isnan(ucv_double_get(v)))
2200                         return NULL;
2201 
2202                 return ucv_get(v);
2203 
2204         case UC_STRING:
2205                 return uc_number_parse(ucv_string_get(v), NULL);
2206 
2207         default:
2208                 return NULL;
2209         }
2210 }
2211 
2212 bool
2213 ucv_compare(int how, uc_value_t *v1, uc_value_t *v2, int *deltap)
2214 {
2215         uc_type_t t1 = ucv_type(v1);
2216         uc_type_t t2 = ucv_type(v2);
2217         uc_value_t *nv1, *nv2;
2218         uint64_t u1, u2;
2219         int64_t n1, n2;
2220         double d1, d2;
2221         int delta;
2222 
2223         /* at least one operand is null and we compare for equality or inequality ... */
2224         if ((!v1 || !v2) && (how == I_EQ || how == I_NE)) {
2225                 delta = (v1 != v2);
2226         }
2227 
2228         /* ... otherwise if both operands are strings, compare bytewise ... */
2229         else if (t1 == UC_STRING && t2 == UC_STRING) {
2230                 u1 = ucv_string_length(v1);
2231                 u2 = ucv_string_length(v2);
2232 
2233                 delta = memcmp(ucv_string_get(v1), ucv_string_get(v2),
2234                         (u1 < u2) ? u1 : u2);
2235 
2236                 if (delta == 0 && u1 < u2)
2237                         delta = -1;
2238                 else if (delta == 0 && u1 > u2)
2239                         delta = 1;
2240         }
2241 
2242         /* handle non-string cases... */
2243         else {
2244                 /* ... both operands are of the same, non-scalar type... */
2245                 if (t1 == t2 && !ucv_is_scalar(v1)) {
2246                         /* ... compare memory addrs */
2247                         if ((uintptr_t)v1 == (uintptr_t)v2)
2248                                 delta = 0;
2249                         else if ((uintptr_t)v1 < (uintptr_t)v2)
2250                                 delta = -1;
2251                         else
2252                                 delta = 1;
2253                 }
2254 
2255                 /* ... operands are of different type or at least one is scalar... */
2256                 else {
2257                         nv1 = ucv_to_number(v1);
2258                         nv2 = ucv_to_number(v2);
2259 
2260                         /* ... at least one of them is NaN (not convertible)... */
2261                         if (!nv1 || !nv2) {
2262                                 ucv_put(nv1);
2263                                 ucv_put(nv2);
2264 
2265                                 if (deltap)
2266                                         *deltap = 2;
2267 
2268                                 /* ... all comparison results except `!=` involving NaN are false */
2269                                 return (how == I_NE);
2270                         }
2271 
2272                         /* ... either of them is a double, compare both as double */
2273                         if (ucv_type(nv1) == UC_DOUBLE || ucv_type(nv2) == UC_DOUBLE) {
2274                                 d1 = ucv_double_get(nv1);
2275                                 d2 = ucv_double_get(nv2);
2276 
2277                                 if (d1 == d2)
2278                                         delta = 0;
2279                                 else if (d1 < d2)
2280                                         delta = -1;
2281                                 else
2282                                         delta = 1;
2283                         }
2284 
2285                         /* ... both are integers... */
2286                         else {
2287                                 n1 = ucv_int64_get(nv1);
2288 
2289                                 /* ... left operand is large positive... */
2290                                 if (errno == ERANGE) {
2291                                         ucv_int64_get(nv2);
2292 
2293                                         /* ... right operand is large positive too... */
2294                                         if (errno == ERANGE) {
2295                                                 /* ... compare both as unsigned */
2296                                                 u1 = ucv_uint64_get(nv1);
2297                                                 u2 = ucv_uint64_get(nv2);
2298 
2299                                                 if (u1 == u2)
2300                                                         delta = 0;
2301                                                 else if (u1 < u2)
2302                                                         delta = -1;
2303                                                 else
2304                                                         delta = 1;
2305                                         }
2306 
2307                                         /* ... right operand is within int64_t range... */
2308                                         else {
2309                                                 /* ... left > right by definition */
2310                                                 delta = 1;
2311                                         }
2312                                 }
2313 
2314                                 /* ... left operand is within int64_t range... */
2315                                 else {
2316                                         n2 = ucv_int64_get(nv2);
2317 
2318                                         /* ... right operand is large positive... */
2319                                         if (errno == ERANGE) {
2320                                                 /* ... left < right by definition */
2321                                                 delta = -1;
2322                                         }
2323 
2324                                         /* ... right operand is within int64_t range... */
2325                                         else {
2326                                                 /* ... compare both as signed */
2327                                                 if (n1 == n2)
2328                                                         delta = 0;
2329                                                 else if (n1 < n2)
2330                                                         delta = -1;
2331                                                 else
2332                                                         delta = 1;
2333                                         }
2334                                 }
2335                         }
2336 
2337                         ucv_put(nv1);
2338                         ucv_put(nv2);
2339                 }
2340         }
2341 
2342         if (deltap)
2343                 *deltap = delta;
2344 
2345         switch (how) {
2346         case I_LT:
2347                 return (delta < 0);
2348 
2349         case I_LE:
2350                 return (delta <= 0);
2351 
2352         case I_GT:
2353                 return (delta > 0);
2354 
2355         case I_GE:
2356                 return (delta >= 0);
2357 
2358         case I_EQ:
2359                 return (delta == 0);
2360 
2361         case I_NE:
2362                 return (delta != 0);
2363 
2364         default:
2365                 return false;
2366         }
2367 }
2368 
2369 
2370 static char *
2371 ucv_key_to_string(uc_vm_t *vm, uc_value_t *val)
2372 {
2373         if (ucv_type(val) != UC_STRING)
2374                 return ucv_to_string(vm, val);
2375 
2376         return NULL;
2377 }
2378 
2379 static int64_t
2380 ucv_key_to_index(uc_value_t *val)
2381 {
2382         const char *k;
2383         int64_t idx;
2384         double d;
2385         char *e;
2386 
2387         /* only consider doubles with integer values as array keys */
2388         if (ucv_type(val) == UC_DOUBLE) {
2389                 d = ucv_double_get(val);
2390 
2391                 if (trunc(d) != d)
2392                         return INT64_MIN;
2393 
2394                 return (int64_t)d;
2395         }
2396         else if (ucv_type(val) == UC_INTEGER) {
2397                 return ucv_int64_get(val);
2398         }
2399         else if (ucv_type(val) == UC_STRING) {
2400                 errno = 0;
2401                 k = ucv_string_get(val);
2402                 idx = strtoll(k, &e, 0);
2403 
2404                 if (errno != 0 || e == k || *e != 0)
2405                         return INT64_MIN;
2406 
2407                 return idx;
2408         }
2409 
2410         return INT64_MIN;
2411 }
2412 
2413 uc_value_t *
2414 ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
2415 {
2416         uc_value_t *o, *v = NULL;
2417         bool found = false;
2418         uc_upvalref_t *ref;
2419         int64_t idx;
2420         char *k;
2421 
2422         if (ucv_type(scope) == UC_ARRAY) {
2423                 idx = ucv_key_to_index(key);
2424 
2425                 if (idx < 0 && idx > INT64_MIN && (uint64_t)llabs(idx) <= ucv_array_length(scope))
2426                         idx += ucv_array_length(scope);
2427 
2428                 if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) {
2429                         v = ucv_array_get(scope, idx);
2430                         found = true;
2431                 }
2432         }
2433 
2434         if (!found) {
2435                 k = ucv_key_to_string(vm, key);
2436 
2437                 for (o = scope; o; o = ucv_prototype_get(o)) {
2438                         if (ucv_type(o) != UC_OBJECT)
2439                                 continue;
2440 
2441                         v = ucv_object_get(o, k ? k : ucv_string_get(key), &found);
2442 
2443                         if (found)
2444                                 break;
2445                 }
2446 
2447                 free(k);
2448         }
2449 
2450         /* Handle upvalue values in objects; under some specific circumstances
2451            objects may contain upvalues, this primarily happens with wildcard module
2452            import namespace dictionaries. */
2453 #ifdef __clang_analyzer__
2454         /* Clang static analyzer does not understand that ucv_type(NULL) can't
2455          * possibly yield UC_UPVALUE. Nudge it. */
2456         if (v != NULL && ucv_type(v) == UC_UPVALUE)
2457 #else
2458         if (ucv_type(v) == UC_UPVALUE)
2459 #endif
2460         {
2461                 ref = (uc_upvalref_t *)v;
2462 
2463                 if (ref->closed)
2464                         return ucv_get(ref->value);
2465                 else if (vm)
2466                         return ucv_get(vm->stack.entries[ref->slot]);
2467                 else
2468                         return NULL;
2469         }
2470 
2471         return ucv_get(v);
2472 }
2473 
2474 uc_value_t *
2475 ucv_key_set(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key, uc_value_t *val)
2476 {
2477         int64_t idx;
2478         char *s;
2479         bool rv;
2480 
2481         if (!key)
2482                 return NULL;
2483 
2484         if (ucv_type(scope) == UC_ARRAY) {
2485                 idx = ucv_key_to_index(key);
2486 
2487                 if (idx < 0 && idx > INT64_MIN && (uint64_t)llabs(idx) <= ucv_array_length(scope))
2488                         idx += ucv_array_length(scope);
2489 
2490                 if (idx < 0 || !ucv_array_set(scope, idx, val))
2491                         return NULL;
2492 
2493                 return ucv_get(val);
2494         }
2495 
2496         s = ucv_key_to_string(vm, key);
2497         rv = ucv_object_add(scope, s ? s : ucv_string_get(key), val);
2498         free(s);
2499 
2500         return rv ? ucv_get(val) : NULL;
2501 }
2502 
2503 bool
2504 ucv_key_delete(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
2505 {
2506         char *s;
2507         bool rv;
2508 
2509         if (!key)
2510                 return NULL;
2511 
2512         s = ucv_key_to_string(vm, key);
2513         rv = ucv_object_delete(scope, s ? s : ucv_string_get(key));
2514         free(s);
2515 
2516         return rv;
2517 }
2518 
2519 
2520 static void
2521 ucv_gc_common(uc_vm_t *vm, bool final)
2522 {
2523         uc_weakref_t *ref, *tmp;
2524         uc_value_t *val;
2525         size_t i;
2526 
2527         vm->alloc_refs = 0;
2528 
2529         /* back out early if value list is uninitialized */
2530         if (!vm->values.prev || !vm->values.next)
2531                 return;
2532 
2533         if (!final) {
2534                 /* mark reachable objects */
2535                 ucv_gc_mark(vm->globals);
2536                 ucv_gc_mark(vm->registry);
2537                 ucv_gc_mark(vm->signal.handler);
2538                 ucv_gc_mark(vm->exception.stacktrace);
2539 
2540                 for (i = 0; i < vm->callframes.count; i++) {
2541                         ucv_gc_mark(vm->callframes.entries[i].ctx);
2542 
2543                         if (vm->callframes.entries[i].closure)
2544                                 ucv_gc_mark(&vm->callframes.entries[i].closure->header);
2545 
2546                         if (vm->callframes.entries[i].cfunction)
2547                                 ucv_gc_mark(&vm->callframes.entries[i].cfunction->header);
2548                 }
2549 
2550                 for (i = 0; i < vm->stack.count; i++)
2551                         ucv_gc_mark(vm->stack.entries[i]);
2552 
2553                 for (i = 0; i < vm->restypes.count; i++)
2554                         ucv_gc_mark(vm->restypes.entries[i]->proto);
2555 
2556                 /* mark no-gc resources with embedded values */
2557                 for (ref = vm->values.prev; ref != &vm->values; ref = ref->prev) {
2558                         val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2559                         if (ucv_type(val) != UC_RESOURCE)
2560                                 break;
2561 
2562                         if (ucv_resource_is_persistent(val))
2563                                 ucv_gc_mark(val);
2564                 }
2565         }
2566 
2567         /* unref unreachable objects */
2568         for (ref = vm->values.next; ref != &vm->values; ref = ref->next) {
2569                 val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2570 
2571                 if (ucv_is_marked(val))
2572                         ucv_clear_mark(val);
2573                 else
2574                         ucv_free(val, true);
2575         }
2576 
2577         /* free destroyed objects */
2578         for (ref = vm->values.next, tmp = ref->next; ref != &vm->values; ref = tmp, tmp = tmp->next) {
2579                 val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2580 
2581                 if (val->type == UC_NULL) {
2582                         ucv_unref(ref);
2583                         free(val);
2584                 }
2585         }
2586 }
2587 
2588 void
2589 ucv_gc(uc_vm_t *vm)
2590 {
2591         ucv_gc_common(vm, false);
2592 }
2593 
2594 void
2595 ucv_freeall(uc_vm_t *vm)
2596 {
2597         ucv_gc_common(vm, true);
2598 }
2599 
2600 void
2601 uc_search_path_init(uc_search_path_t *search_path)
2602 {
2603         size_t i;
2604 
2605         for (i = 0; i < ARRAY_SIZE(uc_default_search_path); i++)
2606                 uc_vector_push(search_path, xstrdup(uc_default_search_path[i]));
2607 }
2608 
2609 
2610 static __thread uc_thread_context_t *tls_ctx;
2611 
2612 uc_thread_context_t *
2613 uc_thread_context_get(void)
2614 {
2615         if (tls_ctx == NULL) {
2616                 tls_ctx = xalloc(sizeof(*tls_ctx));
2617                 tls_ctx->object_iterators.prev = &tls_ctx->object_iterators;
2618                 tls_ctx->object_iterators.next = &tls_ctx->object_iterators;
2619         }
2620 
2621         return tls_ctx;
2622 }
2623 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt