• 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                 array->proto = proto;
1489 
1490                 return true;
1491 
1492         case UC_OBJECT:
1493                 object = (uc_object_t *)uv;
1494                 object->proto = proto;
1495 
1496                 return true;
1497 
1498         default:
1499                 return false;
1500         }
1501 }
1502 
1503 uc_value_t *
1504 ucv_property_get(uc_value_t *uv, const char *key)
1505 {
1506         uc_value_t *val;
1507         bool found;
1508 
1509         for (; uv; uv = ucv_prototype_get(uv)) {
1510                 val = ucv_object_get(uv, key, &found);
1511 
1512                 if (found)
1513                         return val;
1514         }
1515 
1516         return NULL;
1517 }
1518 
1519 
1520 uc_value_t *
1521 ucv_from_json(uc_vm_t *vm, json_object *jso)
1522 {
1523         //uc_array_t *arr;
1524         uc_value_t *uv, *item;
1525         int64_t n;
1526         size_t i;
1527 
1528         switch (json_object_get_type(jso)) {
1529         case json_type_null:
1530                 return NULL;
1531 
1532         case json_type_boolean:
1533                 return ucv_boolean_new(json_object_get_boolean(jso));
1534 
1535         case json_type_double:
1536                 return ucv_double_new(json_object_get_double(jso));
1537 
1538         case json_type_int:
1539                 n = json_object_get_int64(jso);
1540 
1541                 if (n == INT64_MAX)
1542                         return ucv_uint64_new(json_object_get_uint64(jso));
1543 
1544                 return ucv_int64_new(n);
1545 
1546         case json_type_object:
1547                 uv = ucv_object_new(vm);
1548 
1549                 json_object_object_foreach(jso, key, val) {
1550                         item = ucv_from_json(vm, val);
1551 
1552                         if (!ucv_object_add(uv, key, item))
1553                                 ucv_put(item);
1554 
1555 #ifdef __clang_analyzer__
1556                         /* Clang static analyzer does not understand that the object retains
1557                          * our item so pretend to free it here to suppress the false positive
1558                          * memory leak warning. */
1559                         ucv_put(item);
1560 #endif
1561                 }
1562 
1563                 return uv;
1564 
1565         case json_type_array:
1566                 /* XXX
1567                 arr = (uc_array_t *)ucv_array_new_length(vm, json_object_array_length(jso));
1568 
1569                 for (i = 0; i < arr->count; i++)
1570                         arr->entries[i] = ucv_from_json(vm, json_object_array_get_idx(jso, i));
1571 
1572                 return &arr->header;
1573                 */
1574                 uv = ucv_array_new(vm);
1575 
1576                 for (i = 0; i < json_object_array_length(jso); i++) {
1577                         item = ucv_from_json(vm, json_object_array_get_idx(jso, i));
1578 
1579                         if (!ucv_array_push(uv, item))
1580                                 ucv_put(item);
1581 
1582 #ifdef __clang_analyzer__
1583                         /* Clang static analyzer does not understand that the array retains
1584                          * our item so pretend to free it here to suppress the false positive
1585                          * memory leak warning. */
1586                         ucv_put(item);
1587 #endif
1588                 }
1589 
1590                 return uv;
1591 
1592         case json_type_string:
1593                 return ucv_string_new_length(json_object_get_string(jso), json_object_get_string_len(jso));
1594         }
1595 
1596         return NULL;
1597 }
1598 
1599 json_object *
1600 ucv_to_json(uc_value_t *uv)
1601 {
1602         uc_regexp_t *regexp;
1603         uc_array_t *array;
1604         json_object *jso;
1605         size_t i;
1606         char *s;
1607 
1608         switch (ucv_type(uv)) {
1609         case UC_BOOLEAN:
1610                 return json_object_new_boolean(ucv_boolean_get(uv));
1611 
1612         case UC_INTEGER:
1613                 if (ucv_is_u64(uv))
1614                         return json_object_new_uint64(ucv_uint64_get(uv));
1615 
1616                 return json_object_new_int64(ucv_int64_get(uv));
1617 
1618         case UC_DOUBLE:
1619                 return json_object_new_double(ucv_double_get(uv));
1620 
1621         case UC_STRING:
1622                 return json_object_new_string_len(ucv_string_get(uv), ucv_string_length(uv));
1623 
1624         case UC_ARRAY:
1625                 array = (uc_array_t *)uv;
1626                 jso = json_object_new_array_ext(array->count);
1627 
1628                 for (i = 0; i < array->count; i++)
1629                         json_object_array_put_idx(jso, i, ucv_to_json(array->entries[i]));
1630 
1631                 return jso;
1632 
1633         case UC_OBJECT:
1634                 jso = json_object_new_object();
1635 
1636                 ucv_object_foreach(uv, key, val)
1637                         json_object_object_add(jso, key, ucv_to_json(val));
1638 
1639                 return jso;
1640 
1641         case UC_REGEXP:
1642                 regexp = (uc_regexp_t *)uv;
1643                 i = asprintf(&s, "/%s/%s%s%s",
1644                         regexp->source,
1645                         regexp->global ? "g" : "",
1646                         regexp->icase ? "i" : "",
1647                         regexp->newline ? "s" : "");
1648 
1649                 if (i <= 0)
1650                         return NULL;
1651 
1652                 jso = json_object_new_string_len(s, i);
1653 
1654                 free(s);
1655 
1656                 return jso;
1657 
1658         case UC_CLOSURE:
1659         case UC_CFUNCTION:
1660         case UC_RESOURCE:
1661         case UC_UPVALUE:
1662         case UC_PROGRAM:
1663         case UC_SOURCE:
1664         case UC_NULL:
1665                 return NULL;
1666         }
1667 
1668         return NULL;
1669 }
1670 
1671 static void
1672 ucv_to_string_json_encoded(uc_stringbuf_t *pb, const char *s, size_t len, bool regexp)
1673 {
1674         size_t i;
1675 
1676         if (!regexp)
1677                 ucv_stringbuf_append(pb, "\"");
1678 
1679         for (i = 0; s != NULL && i < len; i++, s++) {
1680                 switch (*s) {
1681                 case '"':
1682                         ucv_stringbuf_append(pb, "\\\"");
1683                         break;
1684 
1685                 case '\\':
1686                         ucv_stringbuf_append(pb, "\\\\");
1687                         break;
1688 
1689                 case '\b':
1690                         ucv_stringbuf_append(pb, "\\b");
1691                         break;
1692 
1693                 case '\f':
1694                         ucv_stringbuf_append(pb, "\\f");
1695                         break;
1696 
1697                 case '\n':
1698                         ucv_stringbuf_append(pb, "\\n");
1699                         break;
1700 
1701                 case '\r':
1702                         ucv_stringbuf_append(pb, "\\r");
1703                         break;
1704 
1705                 case '\t':
1706                         ucv_stringbuf_append(pb, "\\t");
1707                         break;
1708 
1709                 case '/':
1710                         ucv_stringbuf_append(pb, "/");
1711                         break;
1712 
1713                 default:
1714                         if ((unsigned char)*s < 0x20)
1715                                 ucv_stringbuf_printf(pb, "\\u%04x", (unsigned char)*s);
1716                         else
1717                                 ucv_stringbuf_addstr(pb, s, 1);
1718 
1719                         break;
1720                 }
1721         }
1722 
1723         if (!regexp)
1724                 ucv_stringbuf_append(pb, "\"");
1725 }
1726 
1727 static bool
1728 ucv_call_tostring(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json)
1729 {
1730         uc_value_t *proto = ucv_prototype_get(uv);
1731         uc_value_t *tostr = ucv_object_get(proto, "tostring", NULL);
1732         uc_value_t *str;
1733         size_t l;
1734         char *s;
1735 
1736         if (!ucv_is_callable(tostr))
1737                 return false;
1738 
1739         uc_vm_stack_push(vm, ucv_get(uv));
1740         uc_vm_stack_push(vm, ucv_get(tostr));
1741 
1742         if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE)
1743                 return false;
1744 
1745         str = uc_vm_stack_pop(vm);
1746 
1747         if (ucv_type(str) == UC_STRING) {
1748                 s = ucv_string_get(str);
1749                 l = ucv_string_length(str);
1750 
1751                 if (json)
1752                         ucv_to_string_json_encoded(pb, s, l, false);
1753                 else if (s)
1754                         ucv_stringbuf_addstr(pb, s, l);
1755         }
1756         else if (json) {
1757                 ucv_stringbuf_append(pb, "\"\"");
1758         }
1759 
1760         ucv_put(str);
1761 
1762         return true;
1763 }
1764 
1765 void
1766 _ucv_stringbuf_append(uc_stringbuf_t *pb, const char *str, size_t len)
1767 {
1768         printbuf_memappend_fast(pb, str, (int)len);
1769 }
1770 
1771 static void
1772 ucv_to_stringbuf_add_padding(uc_stringbuf_t *pb, char pad_char, size_t pad_size)
1773 {
1774         if (pad_char != '\0' && pad_char != '\1') {
1775                 ucv_stringbuf_append(pb, "\n");
1776                 printbuf_memset(pb, -1, pad_char, pad_size);
1777         }
1778         else {
1779                 ucv_stringbuf_append(pb, " ");
1780         }
1781 }
1782 
1783 static void
1784 ucv_to_stringbuf_add_double(uc_stringbuf_t *pb, double val, bool json)
1785 {
1786         int len = ucv_stringbuf_printf(pb, "%.14g", val);
1787 
1788         if (!json)
1789                 return;
1790 
1791         for (char *p = pb->buf + pb->bpos - len; len > 0; len--, p++)
1792                 if (*p == '.' || *p == 'e')
1793                         return;
1794 
1795         ucv_stringbuf_append(pb, ".0");
1796 }
1797 
1798 void
1799 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)
1800 {
1801         bool json = (pad_char != '\0');
1802         uc_resource_type_t *restype;
1803         uc_cfunction_t *cfunction;
1804         uc_function_t *function;
1805         uc_closure_t *closure;
1806         uc_regexp_t *regexp;
1807         uc_value_t *argname;
1808         uc_upvalref_t *ref;
1809         uc_array_t *array;
1810         size_t i, l;
1811         double d;
1812         char *s;
1813 
1814         if (ucv_is_marked(uv)) {
1815                 ucv_stringbuf_append(pb, "null");
1816 
1817                 return;
1818         }
1819 
1820         if (vm != NULL && ucv_call_tostring(vm, pb, uv, json))
1821                 return;
1822 
1823         ucv_set_mark(uv);
1824 
1825         switch (ucv_type(uv)) {
1826         case UC_NULL:
1827                 ucv_stringbuf_append(pb, "null");
1828                 break;
1829 
1830         case UC_BOOLEAN:
1831                 if (ucv_boolean_get(uv))
1832                         ucv_stringbuf_append(pb, "true");
1833                 else
1834                         ucv_stringbuf_append(pb, "false");
1835                 break;
1836 
1837         case UC_INTEGER:
1838                 if (ucv_is_u64(uv))
1839                         ucv_stringbuf_printf(pb, "%" PRIu64, ucv_uint64_get(uv));
1840                 else
1841                         ucv_stringbuf_printf(pb, "%" PRId64, ucv_int64_get(uv));
1842                 break;
1843 
1844         case UC_DOUBLE:
1845                 d = ucv_double_get(uv);
1846 
1847                 if (json && isnan(d))
1848                         ucv_stringbuf_append(pb, "\"NaN\"");
1849                 else if (json && d == INFINITY)
1850                         ucv_stringbuf_append(pb, "1e309");
1851                 else if (json && d == -INFINITY)
1852                         ucv_stringbuf_append(pb, "-1e309");
1853                 else if (isnan(d))
1854                         ucv_stringbuf_append(pb, "NaN");
1855                 else if (d == INFINITY)
1856                         ucv_stringbuf_append(pb, "Infinity");
1857                 else if (d == -INFINITY)
1858                         ucv_stringbuf_append(pb, "-Infinity");
1859                 else
1860                         ucv_to_stringbuf_add_double(pb, d, json);
1861 
1862                 break;
1863 
1864         case UC_STRING:
1865                 s = ucv_string_get(uv);
1866                 l = ucv_string_length(uv);
1867 
1868                 if (s) {
1869                         if (json)
1870                                 ucv_to_string_json_encoded(pb, s, l, false);
1871                         else
1872                                 ucv_stringbuf_addstr(pb, s, l);
1873                 }
1874 
1875                 break;
1876 
1877         case UC_ARRAY:
1878                 array = (uc_array_t *)uv;
1879 
1880                 ucv_stringbuf_append(pb, "[");
1881 
1882                 for (i = 0; i < array->count; i++) {
1883                         if (i)
1884                                 ucv_stringbuf_append(pb, ",");
1885 
1886                         ucv_to_stringbuf_add_padding(pb, pad_char, (depth + 1) * pad_size);
1887                         ucv_to_stringbuf_formatted(vm, pb, array->entries[i], depth + 1, pad_char ? pad_char : '\1', pad_size);
1888                 }
1889 
1890                 ucv_to_stringbuf_add_padding(pb, pad_char, depth * pad_size);
1891                 ucv_stringbuf_append(pb, "]");
1892                 break;
1893 
1894         case UC_OBJECT:
1895                 ucv_stringbuf_append(pb, "{");
1896 
1897                 i = 0;
1898                 ucv_object_foreach(uv, key, val) {
1899                         if (i++)
1900                                 ucv_stringbuf_append(pb, ",");
1901 
1902                         ucv_to_stringbuf_add_padding(pb, pad_char, (depth + 1) * pad_size);
1903                         ucv_to_string_json_encoded(pb, key, strlen(key), false);
1904                         ucv_stringbuf_append(pb, ": ");
1905                         ucv_to_stringbuf_formatted(vm, pb, val, depth + 1, pad_char ? pad_char : '\1', pad_size);
1906                 }
1907 
1908                 ucv_to_stringbuf_add_padding(pb, pad_char, depth * pad_size);
1909                 ucv_stringbuf_append(pb, "}");
1910                 break;
1911 
1912         case UC_REGEXP:
1913                 regexp = (uc_regexp_t *)uv;
1914 
1915                 if (json)
1916                         ucv_stringbuf_append(pb, "\"");
1917 
1918                 ucv_stringbuf_append(pb, "/");
1919                 ucv_to_string_json_encoded(pb, regexp->source, strlen(regexp->source), true);
1920                 ucv_stringbuf_append(pb, "/");
1921 
1922                 if (regexp->global)
1923                         ucv_stringbuf_append(pb, "g");
1924 
1925                 if (regexp->icase)
1926                         ucv_stringbuf_append(pb, "i");
1927 
1928                 if (regexp->newline)
1929                         ucv_stringbuf_append(pb, "s");
1930 
1931                 if (json)
1932                         ucv_stringbuf_append(pb, "\"");
1933 
1934                 break;
1935 
1936         case UC_CLOSURE:
1937                 closure = (uc_closure_t *)uv;
1938                 function = closure->function;
1939 
1940                 if (json)
1941                         ucv_stringbuf_append(pb, "\"");
1942 
1943                 if (!closure->is_arrow) {
1944                         ucv_stringbuf_append(pb, "function");
1945 
1946                         if (function->name[0]) {
1947                                 ucv_stringbuf_append(pb, " ");
1948                                 ucv_stringbuf_addstr(pb, function->name, strlen(function->name));
1949                         }
1950                 }
1951 
1952                 ucv_stringbuf_append(pb, "(");
1953 
1954                 for (i = 1; i <= function->nargs; i++) {
1955                         argname = uc_chunk_debug_get_variable(&function->chunk, i - 1, i, false);
1956 
1957                         if (i > 1)
1958                                 ucv_stringbuf_append(pb, ", ");
1959 
1960                         if (i == function->nargs && function->vararg)
1961                                 ucv_stringbuf_append(pb, "...");
1962 
1963                         if (argname) {
1964                                 s = ucv_string_get(argname);
1965                                 l = ucv_string_length(argname);
1966 
1967                                 if (s)
1968                                         ucv_stringbuf_addstr(pb, s, l);
1969 
1970                                 ucv_put(argname);
1971 
1972                                 continue;
1973                         }
1974 
1975                         ucv_stringbuf_printf(pb, "[arg%zu]", i);
1976                 }
1977 
1978                 ucv_stringbuf_printf(pb, ")%s { ... }%s",
1979                         closure->is_arrow ? " =>" : "",
1980                         json ? "\"" : "");
1981 
1982                 break;
1983 
1984         case UC_CFUNCTION:
1985                 cfunction = (uc_cfunction_t *)uv;
1986 
1987                 ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s",
1988                         json ? "\"" : "",
1989                         cfunction->name[0] ? " " : "",
1990                         cfunction->name[0] ? cfunction->name : "",
1991                         json ? "\"" : "");
1992 
1993                 break;
1994 
1995         case UC_RESOURCE:
1996                 restype = ucv_resource_type(uv);
1997 
1998                 ucv_stringbuf_printf(pb, "%s<%s %p>%s",
1999                         json ? "\"" : "",
2000                         restype ? restype->name : "resource",
2001                         ucv_resource_data(uv, NULL),
2002                         json ? "\"" : "");
2003 
2004                 break;
2005 
2006         case UC_UPVALUE:
2007                 ref = (uc_upvalref_t *)uv;
2008 
2009                 if (ref->closed)
2010                         ucv_to_stringbuf_formatted(vm, pb, ref->value, depth, pad_char, pad_size);
2011                 else if (vm != NULL && ref->slot < vm->stack.count)
2012                         ucv_to_stringbuf_formatted(vm, pb, vm->stack.entries[ref->slot], depth, pad_char, pad_size);
2013                 else
2014                         ucv_stringbuf_printf(pb, "%s<upvalref %p>%s",
2015                                 json ? "\"" : "",
2016                                 uv,
2017                                 json ? "\"" : "");
2018 
2019                 break;
2020 
2021         case UC_PROGRAM:
2022                 ucv_stringbuf_printf(pb, "%s<program %p>%s",
2023                         json ? "\"" : "",
2024                         uv,
2025                         json ? "\"" : "");
2026 
2027                 break;
2028 
2029         case UC_SOURCE:
2030                 ucv_stringbuf_printf(pb, "%s<source %p>%s",
2031                         json ? "\"" : "",
2032                         uv,
2033                         json ? "\"" : "");
2034         }
2035 
2036         ucv_clear_mark(uv);
2037 }
2038 
2039 static char *
2040 ucv_to_string_any(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t pad_size)
2041 {
2042         uc_stringbuf_t *pb = xprintbuf_new();
2043         char *rv;
2044 
2045         ucv_to_stringbuf_formatted(vm, pb, uv, 0, pad_char, pad_size);
2046 
2047         rv = pb->buf;
2048 
2049         free(pb);
2050 
2051         return rv;
2052 }
2053 
2054 char *
2055 ucv_to_string(uc_vm_t *vm, uc_value_t *uv)
2056 {
2057         return ucv_to_string_any(vm, uv, '\0', 0);
2058 }
2059 
2060 char *
2061 ucv_to_jsonstring_formatted(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t pad_size)
2062 {
2063         return ucv_to_string_any(vm, uv, pad_char ? pad_char : '\1', pad_size);
2064 }
2065 
2066 
2067 bool
2068 ucv_is_equal(uc_value_t *uv1, uc_value_t *uv2)
2069 {
2070         uc_type_t t1 = ucv_type(uv1);
2071         uc_type_t t2 = ucv_type(uv2);
2072         const char *s1, *s2;
2073         uint64_t u1, u2;
2074         int64_t n1, n2;
2075         bool b1, b2;
2076 
2077         if (t1 != t2)
2078                 return false;
2079 
2080         if (t1 != UC_DOUBLE && uv1 == uv2)
2081                 return true;
2082 
2083         switch (t1) {
2084         case UC_NULL:
2085                 return true;
2086 
2087         case UC_BOOLEAN:
2088                 return ucv_boolean_get(uv1) == ucv_boolean_get(uv2);
2089 
2090         case UC_DOUBLE:
2091                 return ucv_double_get(uv1) == ucv_double_get(uv2);
2092 
2093         case UC_INTEGER:
2094                 n1 = ucv_int64_get(uv1);
2095                 b1 = (errno == 0);
2096 
2097                 n2 = ucv_int64_get(uv2);
2098                 b2 = (errno == 0);
2099 
2100                 if (b1 && b2)
2101                         return (n1 == n2);
2102 
2103                 u1 = ucv_uint64_get(uv1);
2104                 b1 = (errno == 0);
2105 
2106                 u2 = ucv_uint64_get(uv2);
2107                 b2 = (errno == 0);
2108 
2109                 if (b1 && b2)
2110                         return (u1 == u2);
2111 
2112                 return false;
2113 
2114         case UC_STRING:
2115                 s1 = ucv_string_get(uv1);
2116                 s2 = ucv_string_get(uv2);
2117                 u1 = ucv_string_length(uv1);
2118                 u2 = ucv_string_length(uv2);
2119 
2120                 if (s1 == NULL || s2 == NULL || u1 != u2)
2121                         return false;
2122 
2123                 return (memcmp(s1, s2, u1) == 0);
2124 
2125         case UC_ARRAY:
2126                 u1 = ucv_array_length(uv1);
2127                 u2 = ucv_array_length(uv2);
2128 
2129                 if (u1 != u2)
2130                         return false;
2131 
2132                 for (u1 = 0; u1 < u2; u1++)
2133                         if (!ucv_is_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1)))
2134                                 return false;
2135 
2136                 return true;
2137 
2138         case UC_OBJECT:
2139                 u1 = ucv_object_length(uv1);
2140                 u2 = ucv_object_length(uv2);
2141 
2142                 if (u1 != u2)
2143                         return false;
2144 
2145                 ucv_object_foreach(uv1, key, val) {
2146                         if (!ucv_is_equal(val, ucv_object_get(uv2, key, NULL)))
2147                                 return false;
2148                 }
2149 
2150                 ucv_object_foreach(uv2, key2, val2) {
2151                         (void)val2;
2152                         ucv_object_get(uv1, key2, &b1);
2153 
2154                         if (!b1)
2155                                 return false;
2156                 }
2157 
2158                 return true;
2159 
2160         default:
2161                 return false;
2162         }
2163 }
2164 
2165 bool
2166 ucv_is_truish(uc_value_t *val)
2167 {
2168         double d;
2169 
2170         switch (ucv_type(val)) {
2171         case UC_INTEGER:
2172                 if (ucv_is_u64(val))
2173                         return (ucv_uint64_get(val) != 0);
2174 
2175                 return (ucv_int64_get(val) != 0);
2176 
2177         case UC_DOUBLE:
2178                 d = ucv_double_get(val);
2179 
2180                 return (d != 0 && !isnan(d));
2181 
2182         case UC_BOOLEAN:
2183                 return ucv_boolean_get(val);
2184 
2185         case UC_STRING:
2186                 return (ucv_string_length(val) > 0);
2187 
2188         case UC_NULL:
2189                 return false;
2190 
2191         default:
2192                 return true;
2193         }
2194 }
2195 
2196 uc_value_t *
2197 ucv_to_number(uc_value_t *v)
2198 {
2199         switch (ucv_type(v)) {
2200         case UC_NULL:
2201                 return ucv_uint64_new(0);
2202 
2203         case UC_BOOLEAN:
2204                 return ucv_uint64_new(ucv_boolean_get(v));
2205 
2206         case UC_INTEGER:
2207                 return ucv_get(v);
2208 
2209         case UC_DOUBLE:
2210                 if (isnan(ucv_double_get(v)))
2211                         return NULL;
2212 
2213                 return ucv_get(v);
2214 
2215         case UC_STRING:
2216                 return uc_number_parse(ucv_string_get(v), NULL);
2217 
2218         default:
2219                 return NULL;
2220         }
2221 }
2222 
2223 bool
2224 ucv_compare(int how, uc_value_t *v1, uc_value_t *v2, int *deltap)
2225 {
2226         uc_type_t t1 = ucv_type(v1);
2227         uc_type_t t2 = ucv_type(v2);
2228         uc_value_t *nv1, *nv2;
2229         uint64_t u1, u2;
2230         int64_t n1, n2;
2231         double d1, d2;
2232         int delta;
2233 
2234         /* at least one operand is null and we compare for equality or inequality ... */
2235         if ((!v1 || !v2) && (how == I_EQ || how == I_NE)) {
2236                 delta = (v1 != v2);
2237         }
2238 
2239         /* ... otherwise if both operands are strings, compare bytewise ... */
2240         else if (t1 == UC_STRING && t2 == UC_STRING) {
2241                 u1 = ucv_string_length(v1);
2242                 u2 = ucv_string_length(v2);
2243 
2244                 delta = memcmp(ucv_string_get(v1), ucv_string_get(v2),
2245                         (u1 < u2) ? u1 : u2);
2246 
2247                 if (delta == 0 && u1 < u2)
2248                         delta = -1;
2249                 else if (delta == 0 && u1 > u2)
2250                         delta = 1;
2251         }
2252 
2253         /* handle non-string cases... */
2254         else {
2255                 /* ... both operands are of the same, non-scalar type... */
2256                 if (t1 == t2 && !ucv_is_scalar(v1)) {
2257                         /* ... compare memory addrs */
2258                         if ((uintptr_t)v1 == (uintptr_t)v2)
2259                                 delta = 0;
2260                         else if ((uintptr_t)v1 < (uintptr_t)v2)
2261                                 delta = -1;
2262                         else
2263                                 delta = 1;
2264                 }
2265 
2266                 /* ... operands are of different type or at least one is scalar... */
2267                 else {
2268                         nv1 = ucv_to_number(v1);
2269                         nv2 = ucv_to_number(v2);
2270 
2271                         /* ... at least one of them is NaN (not convertible)... */
2272                         if (!nv1 || !nv2) {
2273                                 ucv_put(nv1);
2274                                 ucv_put(nv2);
2275 
2276                                 if (deltap)
2277                                         *deltap = 2;
2278 
2279                                 /* ... all comparison results except `!=` involving NaN are false */
2280                                 return (how == I_NE);
2281                         }
2282 
2283                         /* ... either of them is a double, compare both as double */
2284                         if (ucv_type(nv1) == UC_DOUBLE || ucv_type(nv2) == UC_DOUBLE) {
2285                                 d1 = ucv_double_get(nv1);
2286                                 d2 = ucv_double_get(nv2);
2287 
2288                                 if (d1 == d2)
2289                                         delta = 0;
2290                                 else if (d1 < d2)
2291                                         delta = -1;
2292                                 else
2293                                         delta = 1;
2294                         }
2295 
2296                         /* ... both are integers... */
2297                         else {
2298                                 n1 = ucv_int64_get(nv1);
2299 
2300                                 /* ... left operand is large positive... */
2301                                 if (errno == ERANGE) {
2302                                         ucv_int64_get(nv2);
2303 
2304                                         /* ... right operand is large positive too... */
2305                                         if (errno == ERANGE) {
2306                                                 /* ... compare both as unsigned */
2307                                                 u1 = ucv_uint64_get(nv1);
2308                                                 u2 = ucv_uint64_get(nv2);
2309 
2310                                                 if (u1 == u2)
2311                                                         delta = 0;
2312                                                 else if (u1 < u2)
2313                                                         delta = -1;
2314                                                 else
2315                                                         delta = 1;
2316                                         }
2317 
2318                                         /* ... right operand is within int64_t range... */
2319                                         else {
2320                                                 /* ... left > right by definition */
2321                                                 delta = 1;
2322                                         }
2323                                 }
2324 
2325                                 /* ... left operand is within int64_t range... */
2326                                 else {
2327                                         n2 = ucv_int64_get(nv2);
2328 
2329                                         /* ... right operand is large positive... */
2330                                         if (errno == ERANGE) {
2331                                                 /* ... left < right by definition */
2332                                                 delta = -1;
2333                                         }
2334 
2335                                         /* ... right operand is within int64_t range... */
2336                                         else {
2337                                                 /* ... compare both as signed */
2338                                                 if (n1 == n2)
2339                                                         delta = 0;
2340                                                 else if (n1 < n2)
2341                                                         delta = -1;
2342                                                 else
2343                                                         delta = 1;
2344                                         }
2345                                 }
2346                         }
2347 
2348                         ucv_put(nv1);
2349                         ucv_put(nv2);
2350                 }
2351         }
2352 
2353         if (deltap)
2354                 *deltap = delta;
2355 
2356         switch (how) {
2357         case I_LT:
2358                 return (delta < 0);
2359 
2360         case I_LE:
2361                 return (delta <= 0);
2362 
2363         case I_GT:
2364                 return (delta > 0);
2365 
2366         case I_GE:
2367                 return (delta >= 0);
2368 
2369         case I_EQ:
2370                 return (delta == 0);
2371 
2372         case I_NE:
2373                 return (delta != 0);
2374 
2375         default:
2376                 return false;
2377         }
2378 }
2379 
2380 
2381 static char *
2382 ucv_key_to_string(uc_vm_t *vm, uc_value_t *val)
2383 {
2384         if (ucv_type(val) != UC_STRING)
2385                 return ucv_to_string(vm, val);
2386 
2387         return NULL;
2388 }
2389 
2390 static int64_t
2391 ucv_key_to_index(uc_value_t *val)
2392 {
2393         const char *k;
2394         int64_t idx;
2395         double d;
2396         char *e;
2397 
2398         /* only consider doubles with integer values as array keys */
2399         if (ucv_type(val) == UC_DOUBLE) {
2400                 d = ucv_double_get(val);
2401 
2402                 if (trunc(d) != d)
2403                         return INT64_MIN;
2404 
2405                 return (int64_t)d;
2406         }
2407         else if (ucv_type(val) == UC_INTEGER) {
2408                 return ucv_int64_get(val);
2409         }
2410         else if (ucv_type(val) == UC_STRING) {
2411                 errno = 0;
2412                 k = ucv_string_get(val);
2413                 idx = strtoll(k, &e, 0);
2414 
2415                 if (errno != 0 || e == k || *e != 0)
2416                         return INT64_MIN;
2417 
2418                 return idx;
2419         }
2420 
2421         return INT64_MIN;
2422 }
2423 
2424 uc_value_t *
2425 ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
2426 {
2427         uc_value_t *o, *v = NULL;
2428         bool found = false;
2429         uc_upvalref_t *ref;
2430         int64_t idx;
2431         char *k;
2432 
2433         if (ucv_type(scope) == UC_ARRAY) {
2434                 idx = ucv_key_to_index(key);
2435 
2436                 if (idx < 0 && idx > INT64_MIN && (uint64_t)llabs(idx) <= ucv_array_length(scope))
2437                         idx += ucv_array_length(scope);
2438 
2439                 if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) {
2440                         v = ucv_array_get(scope, idx);
2441                         found = true;
2442                 }
2443         }
2444 
2445         if (!found) {
2446                 k = ucv_key_to_string(vm, key);
2447 
2448                 for (o = scope; o; o = ucv_prototype_get(o)) {
2449                         if (ucv_type(o) != UC_OBJECT)
2450                                 continue;
2451 
2452                         v = ucv_object_get(o, k ? k : ucv_string_get(key), &found);
2453 
2454                         if (found)
2455                                 break;
2456                 }
2457 
2458                 free(k);
2459         }
2460 
2461         /* Handle upvalue values in objects; under some specific circumstances
2462            objects may contain upvalues, this primarily happens with wildcard module
2463            import namespace dictionaries. */
2464 #ifdef __clang_analyzer__
2465         /* Clang static analyzer does not understand that ucv_type(NULL) can't
2466          * possibly yield UC_UPVALUE. Nudge it. */
2467         if (v != NULL && ucv_type(v) == UC_UPVALUE)
2468 #else
2469         if (ucv_type(v) == UC_UPVALUE)
2470 #endif
2471         {
2472                 ref = (uc_upvalref_t *)v;
2473 
2474                 if (ref->closed)
2475                         return ucv_get(ref->value);
2476                 else if (vm)
2477                         return ucv_get(vm->stack.entries[ref->slot]);
2478                 else
2479                         return NULL;
2480         }
2481 
2482         return ucv_get(v);
2483 }
2484 
2485 uc_value_t *
2486 ucv_key_set(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key, uc_value_t *val)
2487 {
2488         int64_t idx;
2489         char *s;
2490         bool rv;
2491 
2492         if (!key)
2493                 return NULL;
2494 
2495         if (ucv_type(scope) == UC_ARRAY) {
2496                 idx = ucv_key_to_index(key);
2497 
2498                 if (idx < 0 && idx > INT64_MIN && (uint64_t)llabs(idx) <= ucv_array_length(scope))
2499                         idx += ucv_array_length(scope);
2500 
2501                 if (idx < 0 || !ucv_array_set(scope, idx, val))
2502                         return NULL;
2503 
2504                 return ucv_get(val);
2505         }
2506 
2507         s = ucv_key_to_string(vm, key);
2508         rv = ucv_object_add(scope, s ? s : ucv_string_get(key), val);
2509         free(s);
2510 
2511         return rv ? ucv_get(val) : NULL;
2512 }
2513 
2514 bool
2515 ucv_key_delete(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
2516 {
2517         char *s;
2518         bool rv;
2519 
2520         if (!key)
2521                 return NULL;
2522 
2523         s = ucv_key_to_string(vm, key);
2524         rv = ucv_object_delete(scope, s ? s : ucv_string_get(key));
2525         free(s);
2526 
2527         return rv;
2528 }
2529 
2530 
2531 static void
2532 ucv_gc_common(uc_vm_t *vm, bool final)
2533 {
2534         uc_weakref_t *ref, *tmp;
2535         uc_value_t *val;
2536         size_t i;
2537 
2538         vm->alloc_refs = 0;
2539 
2540         /* back out early if value list is uninitialized */
2541         if (!vm->values.prev || !vm->values.next)
2542                 return;
2543 
2544         if (!final) {
2545                 /* mark reachable objects */
2546                 ucv_gc_mark(vm->globals);
2547                 ucv_gc_mark(vm->registry);
2548                 ucv_gc_mark(vm->signal.handler);
2549                 ucv_gc_mark(vm->exception.stacktrace);
2550 
2551                 for (i = 0; i < vm->callframes.count; i++) {
2552                         ucv_gc_mark(vm->callframes.entries[i].ctx);
2553 
2554                         if (vm->callframes.entries[i].closure)
2555                                 ucv_gc_mark(&vm->callframes.entries[i].closure->header);
2556 
2557                         if (vm->callframes.entries[i].cfunction)
2558                                 ucv_gc_mark(&vm->callframes.entries[i].cfunction->header);
2559                 }
2560 
2561                 for (i = 0; i < vm->stack.count; i++)
2562                         ucv_gc_mark(vm->stack.entries[i]);
2563 
2564                 for (i = 0; i < vm->restypes.count; i++)
2565                         ucv_gc_mark(vm->restypes.entries[i]->proto);
2566 
2567                 /* mark no-gc resources with embedded values */
2568                 for (ref = vm->values.prev; ref != &vm->values; ref = ref->prev) {
2569                         val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2570                         if (ucv_type(val) != UC_RESOURCE)
2571                                 break;
2572 
2573                         if (ucv_resource_is_persistent(val))
2574                                 ucv_gc_mark(val);
2575                 }
2576         }
2577 
2578         /* unref unreachable objects */
2579         for (ref = vm->values.next; ref != &vm->values; ref = ref->next) {
2580                 val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2581 
2582                 if (ucv_is_marked(val))
2583                         ucv_clear_mark(val);
2584                 else
2585                         ucv_free(val, true);
2586         }
2587 
2588         /* free destroyed objects */
2589         for (ref = vm->values.next, tmp = ref->next; ref != &vm->values; ref = tmp, tmp = tmp->next) {
2590                 val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
2591 
2592                 if (val->type == UC_NULL) {
2593                         ucv_unref(ref);
2594                         free(val);
2595                 }
2596         }
2597 }
2598 
2599 void
2600 ucv_gc(uc_vm_t *vm)
2601 {
2602         ucv_gc_common(vm, false);
2603 }
2604 
2605 void
2606 ucv_freeall(uc_vm_t *vm)
2607 {
2608         ucv_gc_common(vm, true);
2609 }
2610 
2611 void
2612 uc_search_path_init(uc_search_path_t *search_path)
2613 {
2614         size_t i;
2615 
2616         for (i = 0; i < ARRAY_SIZE(uc_default_search_path); i++)
2617                 uc_vector_push(search_path, xstrdup(uc_default_search_path[i]));
2618 }
2619 
2620 
2621 static __thread uc_thread_context_t *tls_ctx;
2622 
2623 uc_thread_context_t *
2624 uc_thread_context_get(void)
2625 {
2626         if (tls_ctx == NULL) {
2627                 tls_ctx = xalloc(sizeof(*tls_ctx));
2628                 tls_ctx->object_iterators.prev = &tls_ctx->object_iterators;
2629                 tls_ctx->object_iterators.next = &tls_ctx->object_iterators;
2630         }
2631 
2632         return tls_ctx;
2633 }
2634 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt