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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt