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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt