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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt