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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt