• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/vm.c

  1 /*
  2  * Copyright (C) 2020-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 <string.h>
 19 #include <assert.h>
 20 #include <ctype.h>
 21 #include <math.h>
 22 #include <errno.h>
 23 #include <limits.h>
 24 #include <fcntl.h>
 25 #include <unistd.h>
 26 
 27 #include "ucode/vm.h"
 28 #include "ucode/compiler.h"
 29 #include "ucode/program.h"
 30 #include "ucode/lib.h" /* uc_error_context_format() */
 31 #include "ucode/platform.h"
 32 
 33 #undef __insn
 34 #define __insn(_name) #_name,
 35 
 36 static const char *insn_names[__I_MAX] = {
 37         __insns
 38 };
 39 
 40 static const int8_t insn_operand_bytes[__I_MAX] = {
 41         [I_LOAD] = 4,
 42         [I_LOAD8] = 1,
 43         [I_LOAD16] = 2,
 44         [I_LOAD32] = 4,
 45 
 46         [I_LREXP] = 4,
 47 
 48         [I_LLOC] = 4,
 49         [I_LVAR] = 4,
 50         [I_LUPV] = 4,
 51 
 52         [I_CLFN] = 4,
 53         [I_ARFN] = 4,
 54 
 55         [I_SLOC] = 4,
 56         [I_SUPV] = 4,
 57         [I_SVAR] = 4,
 58 
 59         [I_ULOC] = 4,
 60         [I_UUPV] = 4,
 61         [I_UVAR] = 4,
 62         [I_UVAL] = 1,
 63 
 64         [I_NARR] = 4,
 65         [I_PARR] = 4,
 66 
 67         [I_NOBJ] = 4,
 68         [I_SOBJ] = 4,
 69 
 70         [I_JMP] = -4,
 71         [I_JMPZ] = -4,
 72         [I_JMPNT] = 4,
 73 
 74         [I_COPY] = 1,
 75 
 76         [I_CALL] = 4,
 77 
 78         [I_IMPORT] = 4,
 79         [I_EXPORT] = 4,
 80         [I_DYNLOAD] = 4
 81 };
 82 
 83 static const char *exception_type_strings[] = {
 84         [EXCEPTION_SYNTAX] = "Syntax error",
 85         [EXCEPTION_RUNTIME] = "Runtime error",
 86         [EXCEPTION_TYPE] = "Type error",
 87         [EXCEPTION_REFERENCE] = "Reference error",
 88         [EXCEPTION_USER] = "Error",
 89         [EXCEPTION_EXIT] = "Exit"
 90 };
 91 
 92 
 93 static const char *
 94 uc_vm_insn_to_name(uc_vm_insn_t insn)
 95 {
 96         if (insn < 0 || insn >= __I_MAX)
 97                 return "(unknown)";
 98 
 99         return insn_names[insn];
100 }
101 
102 static int8_t
103 uc_vm_insn_to_argtype(uc_vm_insn_t insn)
104 {
105         if (insn < 0 || insn >= __I_MAX)
106                 return 0;
107 
108         return insn_operand_bytes[insn];
109 }
110 
111 static void
112 uc_vm_reset_stack(uc_vm_t *vm)
113 {
114         while (vm->stack.count > 0) {
115                 vm->stack.count--;
116                 ucv_put(vm->stack.entries[vm->stack.count]);
117                 vm->stack.entries[vm->stack.count] = NULL;
118         }
119 }
120 
121 static uc_value_t *
122 uc_vm_callframe_pop(uc_vm_t *vm);
123 
124 static void
125 uc_vm_reset_callframes(uc_vm_t *vm)
126 {
127         while (vm->callframes.count > 0)
128                 ucv_put(uc_vm_callframe_pop(vm));
129 }
130 
131 static uc_value_t *
132 uc_vm_alloc_global_scope(uc_vm_t *vm)
133 {
134         uc_value_t *scope, *arr;
135         size_t i;
136 
137         scope = ucv_object_new(vm);
138 
139         /* build default require() search path */
140         arr = ucv_array_new(vm);
141 
142         for (i = 0; i < vm->config->module_search_path.count; i++)
143                 ucv_array_push(arr, ucv_string_new(vm->config->module_search_path.entries[i]));
144 
145         /* register module related constants */
146         ucv_object_add(scope, "REQUIRE_SEARCH_PATH", arr);
147         ucv_object_add(scope, "modules", ucv_object_new(vm));
148 
149         /* register scope math constants */
150         ucv_object_add(scope, "NaN", ucv_double_new(NAN));
151         ucv_object_add(scope, "Infinity", ucv_double_new(INFINITY));
152 
153         /* register global property */
154         ucv_object_add(scope, "global", ucv_get(scope));
155 
156         uc_vm_scope_set(vm, scope);
157 
158         return scope;
159 }
160 
161 static void
162 uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex);
163 
164 static void
165 uc_vm_signal_handler(int sig)
166 {
167         uc_vm_t *vm = uc_thread_context_get()->signal_handler_vm;
168 
169         assert(vm);
170 
171         uc_vm_signal_raise(vm, sig);
172 }
173 
174 static void
175 uc_vm_signal_handlers_setup(uc_vm_t *vm)
176 {
177         uc_thread_context_t *tctx;
178 
179         memset(&vm->signal, 0, sizeof(vm->signal));
180 
181         vm->signal.sigpipe[0] = -1;
182         vm->signal.sigpipe[1] = -1;
183 
184         if (!vm->config->setup_signal_handlers)
185                 return;
186 
187         tctx = uc_thread_context_get();
188 
189         if (tctx->signal_handler_vm)
190                 return;
191 
192         if (pipe2(vm->signal.sigpipe, O_CLOEXEC | O_NONBLOCK) != 0)
193                 return;
194 
195         vm->signal.handler = ucv_array_new_length(vm, UC_SYSTEM_SIGNAL_COUNT);
196 
197         vm->signal.sa.sa_handler = uc_vm_signal_handler;
198         vm->signal.sa.sa_flags = SA_RESTART | SA_ONSTACK;
199         sigemptyset(&vm->signal.sa.sa_mask);
200 
201         tctx->signal_handler_vm = vm;
202 }
203 
204 static void
205 uc_vm_signal_handlers_reset(uc_vm_t *vm)
206 {
207         uc_thread_context_t *tctx = uc_thread_context_get();
208         struct sigaction sa = { 0 };
209         size_t i, signo;
210 
211         if (vm != tctx->signal_handler_vm)
212                 return;
213 
214         sa.sa_handler = SIG_DFL;
215         sigemptyset(&sa.sa_mask);
216 
217         for (signo = 0; signo < ucv_array_length(vm->signal.handler); signo++)
218                 if (ucv_is_callable(ucv_array_get(vm->signal.handler, signo)))
219                         sigaction(signo, &sa, NULL);
220 
221         for (i = 0; i < ARRAY_SIZE(vm->signal.sigpipe); i++) {
222                 if (vm->signal.sigpipe[i] > STDERR_FILENO)
223                         close(vm->signal.sigpipe[i]);
224 
225                 vm->signal.sigpipe[i] = -1;
226         }
227 
228         tctx->signal_handler_vm = NULL;
229 }
230 
231 void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config)
232 {
233         vm->exception.type = EXCEPTION_NONE;
234         vm->exception.message = NULL;
235 
236         vm->config = config ? config : &uc_default_parse_config;
237 
238         vm->open_upvals = NULL;
239 
240         vm->values.prev = &vm->values;
241         vm->values.next = &vm->values;
242 
243         vm->strbuf = NULL;
244 
245         vm->output = stdout;
246 
247         uc_vm_reset_stack(vm);
248 
249         uc_vm_alloc_global_scope(vm);
250 
251         uc_vm_exception_handler_set(vm, uc_vm_output_exception);
252 
253         uc_vm_trace_set(vm, 0);
254 
255         uc_vm_signal_handlers_setup(vm);
256 
257         uc_thread_context_get()->refcount++;
258 }
259 
260 void uc_vm_free(uc_vm_t *vm)
261 {
262         uc_thread_context_t *ctx;
263         uc_upvalref_t *ref;
264         size_t i;
265 
266         uc_vm_signal_handlers_reset(vm);
267 
268         ucv_put(vm->exception.stacktrace);
269         free(vm->exception.message);
270 
271         while (vm->open_upvals) {
272                 ref = vm->open_upvals->next;
273                 ucv_put(&vm->open_upvals->header);
274                 vm->open_upvals = ref;
275         }
276 
277         uc_vm_reset_callframes(vm);
278         uc_vm_reset_stack(vm);
279         uc_vector_clear(&vm->stack);
280         uc_vector_clear(&vm->callframes);
281 
282         printbuf_free(vm->strbuf);
283 
284         ucv_freeall(vm);
285 
286         /* Type prototypes are not on the GC value list, so a ucv_put() during
287          * ucv_freeall()'s retain phase would only mark them UC_NULL and leak
288          * them. Release them here, after the final GC, so the last reference a
289          * GC value may hold (e.g. via proto()) is already gone. */
290         for (i = 0; i < vm->restypes.count; i++) {
291                 ucv_put(vm->restypes.entries[i]->proto);
292                 free(vm->restypes.entries[i]);
293         }
294 
295         uc_vector_clear(&vm->restypes);
296 
297         ctx = uc_thread_context_get();
298 
299         assert(ctx->refcount > 0);
300 
301         if (--ctx->refcount == 0)
302                 uc_thread_context_free();
303 }
304 
305 static uc_chunk_t *
306 uc_vm_frame_chunk(uc_callframe_t *frame)
307 {
308         return frame->closure ? &frame->closure->function->chunk : NULL;
309 }
310 
311 static uc_program_t *
312 uc_vm_frame_program(uc_callframe_t *frame)
313 {
314         return frame->closure ? frame->closure->function->program : NULL;
315 }
316 
317 static uc_source_t *
318 uc_vm_frame_source(uc_callframe_t *frame)
319 {
320         return frame->closure ? uc_program_function_source(frame->closure->function) : NULL;
321 }
322 
323 static uc_callframe_t *
324 uc_vm_current_frame(uc_vm_t *vm)
325 {
326         return uc_vector_last(&vm->callframes);
327 }
328 
329 static uc_program_t *
330 uc_vm_current_program(uc_vm_t *vm)
331 {
332         return uc_vm_frame_program(uc_vm_current_frame(vm));
333 }
334 
335 static bool
336 uc_vm_is_strict(uc_vm_t *vm)
337 {
338         return uc_vm_current_frame(vm)->strict;
339 }
340 
341 static uc_vm_insn_t
342 uc_vm_decode_insn(uc_vm_t *vm, uc_callframe_t *frame, uc_chunk_t *chunk)
343 {
344         uc_vm_insn_t insn;
345         int8_t argtype;
346 
347 #ifndef NDEBUG
348         uint8_t *end = chunk->entries + chunk->count;
349 #endif
350 
351         assert(frame->ip < end);
352 
353         insn = frame->ip[0];
354         frame->ip++;
355 
356         argtype = uc_vm_insn_to_argtype(insn);
357 
358         assert(frame->ip + abs(argtype) <= end);
359 
360         switch (argtype) {
361         case 0:
362                 break;
363 
364         case -4:
365                 vm->arg.s32 = (
366                         frame->ip[0] * 0x1000000UL +
367                         frame->ip[1] * 0x10000UL +
368                         frame->ip[2] * 0x100UL +
369                         frame->ip[3]
370                 ) - 0x7fffffff;
371                 frame->ip += 4;
372                 break;
373 
374         case 1:
375                 vm->arg.u8 = frame->ip[0];
376                 frame->ip++;
377                 break;
378 
379         case 2:
380                 vm->arg.u16 = (
381                         frame->ip[0] * 0x100 +
382                         frame->ip[1]
383                 );
384                 frame->ip += 2;
385                 break;
386 
387         case 4:
388                 vm->arg.u32 = (
389                         frame->ip[0] * 0x1000000UL +
390                         frame->ip[1] * 0x10000UL +
391                         frame->ip[2] * 0x100UL +
392                         frame->ip[3]
393                 );
394                 frame->ip += 4;
395                 break;
396 
397         default:
398                 fprintf(stderr, "Unhandled operand format: %" PRId8 "\n", argtype);
399                 abort();
400         }
401 
402         return insn;
403 }
404 
405 
406 static char *
407 uc_vm_format_val(uc_vm_t *vm, uc_value_t *val)
408 {
409         if (!vm->strbuf)
410                 vm->strbuf = xprintbuf_new();
411         else
412                 printbuf_reset(vm->strbuf);
413 
414         ucv_to_stringbuf(NULL, vm->strbuf, val, true);
415 
416         if (printbuf_length(vm->strbuf) >= 64) {
417                 printbuf_memset(vm->strbuf, 60, '.', 3);
418                 printbuf_memset(vm->strbuf, 63, 0, 1);
419         }
420 
421         return vm->strbuf->buf;
422 }
423 
424 static void
425 uc_vm_frame_dump(uc_vm_t *vm, uc_callframe_t *frame)
426 {
427         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
428         uc_function_t *function;
429         uc_closure_t *closure;
430         uc_upvalref_t *ref;
431         uc_value_t *v;
432         size_t i;
433 
434         fprintf(stderr, "  [*] CALLFRAME[%zx]\n",
435                 frame - vm->callframes.entries);
436 
437         fprintf(stderr, "   |- stackframe %zu/%zu\n",
438                 frame->stackframe, vm->stack.count);
439 
440         fprintf(stderr, "   |- ctx %s\n",
441                 uc_vm_format_val(vm, frame->ctx));
442 
443         if (chunk) {
444                 closure = frame->closure;
445                 function = closure->function;
446 
447                 fprintf(stderr, "   `- %zu upvalues\n",
448                         function->nupvals);
449 
450                 for (i = 0; i < function->nupvals; i++) {
451                         ref = closure->upvals[i];
452                         v = uc_chunk_debug_get_variable(chunk, 0, i, true);
453 
454                         fprintf(stderr, "     [%zu] <%p> %s ",
455                                 i, (void *)ref, uc_vm_format_val(vm, v));
456 
457                         if (!ref) {
458                                 fprintf(stderr, "{unresolved}\n");
459                         }
460                         else if (ref->closed) {
461                                 fprintf(stderr, "{closed} %s\n",
462                                         uc_vm_format_val(vm, ref->value));
463                         }
464                         else {
465                                 fprintf(stderr, "{open[%zu]} %s\n",
466                                         ref->slot,
467                                         uc_vm_format_val(vm, vm->stack.entries[ref->slot]));
468                         }
469 
470                         ucv_put(v);
471                 }
472         }
473 }
474 
475 static uc_value_t *
476 uc_vm_resolve_upval(uc_vm_t *vm, uc_value_t *value)
477 {
478         uc_upvalref_t *ref;
479         uc_value_t *rv;
480 
481 #ifdef __clang_analyzer__
482         /* Clang static analyzer does not understand that ucv_type(NULL) can't
483          * possibly yield UC_UPVALUE. Nudge it. */
484         if (value != NULL && ucv_type(value) == UC_UPVALUE)
485 #else
486         if (ucv_type(value) == UC_UPVALUE)
487 #endif
488         {
489                 ref = (uc_upvalref_t *)value;
490 
491                 if (ref->closed)
492                         rv = ucv_get(ref->value);
493                 else
494                         rv = ucv_get(vm->stack.entries[ref->slot]);
495 
496                 ucv_put(value);
497 
498                 return rv;
499         }
500 
501         return value;
502 }
503 
504 void
505 uc_vm_stack_push(uc_vm_t *vm, uc_value_t *value)
506 {
507         uc_vector_push(&vm->stack, uc_vm_resolve_upval(vm, value));
508 
509         if (vm->trace) {
510                 fprintf(stderr, "  [+%zd] %s\n",
511                         vm->stack.count - 1,
512                         uc_vm_format_val(vm, vm->stack.entries[vm->stack.count - 1]));
513         }
514 }
515 
516 uc_value_t *
517 uc_vm_stack_pop(uc_vm_t *vm)
518 {
519         uc_value_t *rv;
520 
521         vm->stack.count--;
522         rv = vm->stack.entries[vm->stack.count];
523         vm->stack.entries[vm->stack.count] = NULL;
524 
525         if (vm->trace) {
526                 fprintf(stderr, "  [-%zd] %s\n",
527                         vm->stack.count,
528                         uc_vm_format_val(vm, rv));
529         }
530 
531         return rv;
532 }
533 
534 uc_value_t *
535 uc_vm_stack_peek(uc_vm_t *vm, size_t offset)
536 {
537         return vm->stack.entries[vm->stack.count + (-1 - offset)];
538 }
539 
540 static void
541 uc_vm_stack_set(uc_vm_t *vm, size_t offset, uc_value_t *value)
542 {
543         if (vm->trace) {
544                 fprintf(stderr, "  [!%zu] %s\n",
545                         offset,
546                         uc_vm_format_val(vm, value));
547         }
548 
549         ucv_put(vm->stack.entries[offset]);
550         vm->stack.entries[offset] = value;
551 }
552 
553 static void
554 uc_vm_call_native(uc_vm_t *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs)
555 {
556         uc_value_t *res = NULL;
557         uc_callframe_t *frame;
558 
559         /* add new callframe */
560         frame = uc_vector_push(&vm->callframes, {
561                 .stackframe = vm->stack.count - nargs - 1,
562                 .cfunction = fptr,
563                 .closure = NULL,
564                 .ctx = ctx,
565                 .mcall = mcall
566         });
567 
568         if (vm->trace)
569                 uc_vm_frame_dump(vm, frame);
570 
571         res = fptr->cfn(vm, nargs);
572 
573         /* Reset stack, check for callframe depth since an uncatched exception in managed
574          * code executed by fptr->cfn() could've reset the callframe stack already. */
575         if (vm->callframes.count > 0)
576                 ucv_put(uc_vm_callframe_pop(vm));
577 
578         /* push return value */
579         if (!vm->exception.type)
580                 uc_vm_stack_push(vm, res);
581         else
582                 ucv_put(res);
583 }
584 
585 static bool
586 uc_vm_call_function(uc_vm_t *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, size_t argspec)
587 {
588         size_t i, j, stackoff, nargs = argspec & 0xffff;
589         size_t nspreads = (argspec >> 16) & 0x7fff;
590         uc_callframe_t *frame = NULL;
591         uc_value_t *ellip, *arg;
592         uc_function_t *function;
593         uc_closure_t *closure;
594         uint16_t slot, tmp;
595         char *s;
596 
597         /* XXX: make dependent on stack size */
598         if (vm->callframes.count >= 1000) {
599                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Too much recursion");
600                 ucv_put(ctx);
601                 ucv_put(fno);
602 
603                 return false;
604         }
605 
606         stackoff = vm->stack.count - nargs - 1;
607 
608         /* argument list contains spread operations, we need to reshuffle the stack */
609         if (nspreads > 0) {
610                 frame = uc_vm_current_frame(vm);
611 
612                 /* create temporary array */
613                 ellip = ucv_array_new_length(vm, nargs);
614 
615                 /* pop original stack values and push to temp array in reverse order */
616                 for (i = 0; i < nargs; i++)
617                         ucv_array_push(ellip, uc_vm_stack_pop(vm));
618 
619                 /* for each spread value index ... */
620                 for (i = 0, slot = nargs; i < nspreads; i++) {
621                         /* decode stack depth value */
622                         tmp = frame->ip[0] * 0x100 + frame->ip[1];
623                         frame->ip += 2;
624 
625                         /* push each preceeding non-spread value to the stack */
626                         for (j = slot; j > tmp + 1UL; j--)
627                                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, j - 1)));
628 
629                         /* read spread value at index... */
630                         slot = tmp;
631                         arg = ucv_get(ucv_array_get(ellip, slot));
632 
633                         /* ... ensure that it is an array type ... */
634                         if (ucv_type(arg) != UC_ARRAY) {
635                                 s = ucv_to_string(vm, arg);
636                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s);
637                                 free(s);
638                                 ucv_put(ctx);
639                                 ucv_put(fno);
640                                 ucv_put(ellip);
641 
642                                 return false;
643                         }
644 
645                         /* ... and push each spread array value as argument to the stack */
646                         for (j = 0; j < ucv_array_length(arg); j++)
647                                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(arg, j)));
648 
649                         ucv_put(arg);
650                 }
651 
652                 /* push remaining non-spread arguments to the stack */
653                 for (i = slot; i > 0; i--)
654                         uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, i - 1)));
655 
656                 /* free temp array */
657                 ucv_put(ellip);
658 
659                 /* update arg count */
660                 nargs = vm->stack.count - stackoff - 1;
661         }
662 
663         /* is a native function */
664         if (ucv_type(fno) == UC_CFUNCTION) {
665                 uc_vm_call_native(vm, ctx, (uc_cfunction_t *)fno, mcall, nargs);
666 
667                 return true;
668         }
669 
670         if (ucv_type(fno) != UC_CLOSURE) {
671                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "left-hand side is not a function");
672                 ucv_put(ctx);
673                 ucv_put(fno);
674 
675                 return false;
676         }
677 
678         closure = (uc_closure_t *)fno;
679         function = closure->function;
680 
681         /* fewer arguments on stack than function expects => pad */
682         if (nargs < function->nargs) {
683                 for (i = nargs; i < function->nargs; i++) {
684                         if (function->vararg && (i + 1) == function->nargs)
685                                 uc_vm_stack_push(vm, ucv_array_new_length(vm, 0));
686                         else
687                                 uc_vm_stack_push(vm, NULL);
688                 }
689         }
690 
691         /* more arguments on stack than function expects... */
692         else if (nargs > function->nargs - function->vararg) {
693                 /* is a vararg function => pass excess args as array */
694                 if (function->vararg) {
695                         ellip = ucv_array_new_length(vm, nargs - (function->nargs - 1));
696 
697                         for (i = function->nargs; i <= nargs; i++)
698                                 ucv_array_push(ellip, uc_vm_stack_peek(vm, nargs - i));
699 
700                         for (i = function->nargs; i <= nargs; i++)
701                                 uc_vm_stack_pop(vm);
702 
703                         uc_vm_stack_push(vm, ellip);
704                 }
705 
706                 /* static amount of args => drop excess values */
707                 else {
708                         for (i = function->nargs; i < nargs; i++)
709                                 ucv_put(uc_vm_stack_pop(vm));
710                 }
711         }
712 
713         frame = uc_vector_push(&vm->callframes, {
714                 .stackframe = stackoff,
715                 .cfunction = NULL,
716                 .closure = closure,
717                 .ctx = ctx,
718                 .ip = function->chunk.entries,
719                 .mcall = mcall,
720                 .strict = function->strict
721         });
722 
723         if (vm->trace)
724                 uc_vm_frame_dump(vm, frame);
725 
726         return true;
727 }
728 
729 static uc_source_t *last_source = NULL;
730 static size_t last_srcpos = 0;
731 
732 static void
733 uc_dump_insn(uc_vm_t *vm, uint8_t *pos, uc_vm_insn_t insn)
734 {
735         uc_callframe_t *frame = uc_vm_current_frame(vm);
736         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
737         uc_stringbuf_t *buf = NULL;
738         uc_value_t *cnst = NULL;
739         uc_source_t *source;
740         int8_t argtype;
741         size_t srcpos;
742 
743         srcpos = uc_program_function_srcpos(frame->closure->function, pos - chunk->entries);
744         source = uc_vm_frame_source(frame);
745 
746         if (last_srcpos == 0 || last_source != source || srcpos != last_srcpos) {
747                 buf = xprintbuf_new();
748 
749                 uc_source_context_format(buf, source, srcpos, true);
750                 fwrite(buf->buf, 1, printbuf_length(buf), stderr);
751                 printbuf_free(buf);
752 
753                 last_source = source;
754                 last_srcpos = srcpos;
755         }
756 
757         fprintf(stderr, "%08zx  %s", pos - chunk->entries,
758                 uc_vm_insn_to_name(insn));
759 
760         argtype = uc_vm_insn_to_argtype(insn);
761 
762         switch (argtype) {
763         case 0:
764                 break;
765 
766         case -1:
767                 fprintf(stderr, " {%s%hhd}", vm->arg.s8 < 0 ? "" : "+", vm->arg.s8);
768                 break;
769 
770         case -2:
771                 fprintf(stderr, " {%c0x%hx}",
772                         vm->arg.s16 < 0 ? '-' : '+',
773                         (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16));
774                 break;
775 
776         case -4:
777                 fprintf(stderr, " {%c0x%x}",
778                         vm->arg.s32 < 0 ? '-' : '+',
779                         (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32));
780                 break;
781 
782         case 1:
783                 fprintf(stderr, " {%hhu}", vm->arg.u8);
784                 break;
785 
786         case 2:
787                 fprintf(stderr, " {0x%hx}", vm->arg.u16);
788                 break;
789 
790         case 4:
791                 fprintf(stderr, " {0x%x}", vm->arg.u32);
792                 break;
793 
794         default:
795                 fprintf(stderr, " (unknown operand format: %" PRId8 ")", argtype);
796                 break;
797         }
798 
799         switch (insn) {
800         case I_LOAD:
801         case I_LVAR:
802         case I_SVAR:
803                 cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32);
804 
805                 fprintf(stderr, "\t; %s",
806                         cnst ? uc_vm_format_val(vm, cnst) : "(?)");
807 
808                 ucv_put(cnst);
809                 break;
810 
811         case I_LLOC:
812         case I_LUPV:
813         case I_SLOC:
814         case I_SUPV:
815                 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32, (insn == I_LUPV || insn == I_SUPV));
816 
817                 fprintf(stderr, "\t; %s",
818                         cnst ? uc_vm_format_val(vm, cnst) : "(?)");
819 
820                 ucv_put(cnst);
821                 break;
822 
823         case I_ULOC:
824         case I_UUPV:
825                 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32 & 0x00ffffff, (insn == I_UUPV));
826                 /* fall through */
827 
828         case I_UVAR:
829                 if (!cnst)
830                         cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32 & 0x00ffffff);
831 
832                 fprintf(stderr, "\t; %s (%s)",
833                         cnst ? uc_vm_format_val(vm, cnst) : "(?)",
834                         uc_vm_insn_to_name(vm->arg.u32 >> 24));
835 
836                 ucv_put(cnst);
837                 break;
838 
839         case I_UVAL:
840                 fprintf(stderr, "\t; (%s)", uc_vm_insn_to_name(vm->arg.u8));
841                 break;
842 
843         default:
844                 break;
845         }
846 
847         fprintf(stderr, "\n");
848 }
849 
850 static uc_value_t *
851 uc_vm_exception_tostring(uc_vm_t *vm, size_t nargs)
852 {
853         uc_callframe_t *frame = uc_vm_current_frame(vm);
854         uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL);
855 
856         return message ? ucv_get(message) : ucv_string_new("Exception");
857 }
858 
859 uc_value_t *
860 uc_vm_exception_object(uc_vm_t *vm)
861 {
862         uc_exception_type_t type = vm->exception.type;
863         const char *message = vm->exception.message;
864         uc_value_t *stacktrace = vm->exception.stacktrace;
865         uc_value_t *exception_prototype = uc_vm_registry_get(vm, "vm.exception.proto");
866         uc_value_t *exo;
867 
868         if (exception_prototype == NULL) {
869                 exception_prototype = ucv_object_new(vm);
870 
871                 ucv_object_add(exception_prototype, "tostring",
872                         ucv_cfunction_new("tostring", uc_vm_exception_tostring));
873 
874                 uc_vm_registry_set(vm, "vm.exception.proto", exception_prototype);
875         }
876 
877         exo = ucv_object_new(vm);
878 
879         ucv_object_add(exo, "type", ucv_string_new(exception_type_strings[type]));
880         ucv_object_add(exo, "message", ucv_string_new(message));
881         ucv_object_add(exo, "stacktrace", ucv_get(stacktrace));
882 
883         ucv_prototype_set(exo, ucv_get(exception_prototype));
884 
885         return exo;
886 }
887 
888 static void
889 uc_vm_clear_exception(uc_vm_t *vm)
890 {
891         vm->exception.type = EXCEPTION_NONE;
892 
893         ucv_put(vm->exception.stacktrace);
894         vm->exception.stacktrace = NULL;
895 
896         free(vm->exception.message);
897         vm->exception.message = NULL;
898 }
899 
900 static bool
901 uc_vm_handle_exception(uc_vm_t *vm)
902 {
903         uc_callframe_t *frame = NULL;
904         uc_chunk_t *chunk = NULL;
905         uc_value_t *exo;
906         size_t i, pos;
907 
908         if (vm->callframes.count)
909                 frame = uc_vm_current_frame(vm);
910 
911         if (!frame || !frame->closure)
912                 return false;
913 
914         chunk = uc_vm_frame_chunk(frame);
915         pos = frame->ip - chunk->entries;
916 
917         /* iterate the known exception ranges, see if the current ip falls into any of them */
918         for (i = 0; i < chunk->ehranges.count; i++) {
919                 /* skip nonmatching ranges */
920                 if (pos < chunk->ehranges.entries[i].from ||
921                     pos >= chunk->ehranges.entries[i].to)
922                         continue;
923 
924                 /* we found a matching range... first unwind stack */
925                 while (vm->stack.count > frame->stackframe + chunk->ehranges.entries[i].slot)
926                         ucv_put(uc_vm_stack_pop(vm));
927 
928                 /* prepare exception object and expose it to user handler code */
929                 exo = uc_vm_exception_object(vm);
930 
931                 uc_vm_stack_push(vm, exo);
932 
933                 /* reset exception information */
934                 uc_vm_clear_exception(vm);
935 
936                 /* jump to exception handler */
937                 if (chunk->ehranges.entries[i].target >= chunk->count) {
938                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
939                         return false;
940                 }
941 
942 #if 0
943                 if (vm->trace && chunk->entries + chunk->ehranges.entries[i].target > frame->ip) {
944                         while (frame->ip < chunk->entries + chunk->ehranges.entries[i].target) {
945                                 fprintf(stderr, "(eh:skip) [%p:%zu] ", chunk, frame->ip - chunk->entries);
946                                 uc_dump_insn(vm, frame->ip, uc_vm_decode_insn(vm, frame, chunk));
947                         }
948                 }
949 #endif
950 
951                 frame->ip = chunk->entries + chunk->ehranges.entries[i].target;
952 
953                 return true;
954         }
955 
956         return false;
957 }
958 
959 static uc_value_t *
960 uc_vm_capture_stacktrace(uc_vm_t *vm, size_t i)
961 {
962         uc_value_t *stacktrace, *entry, *last = NULL;
963         uc_function_t *function;
964         uc_callframe_t *frame;
965         uc_source_t *source;
966         size_t off, srcpos;
967         char *name;
968 
969         stacktrace = ucv_array_new(vm);
970 
971         for (; i > 0; i--) {
972                 frame = &vm->callframes.entries[i - 1];
973                 entry = ucv_object_new(vm);
974 
975                 if (frame->closure) {
976                         function = frame->closure->function;
977                         source = uc_program_function_source(function);
978 
979                         off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1;
980                         srcpos = uc_program_function_srcpos(function, off);
981 
982                         ucv_object_add(entry, "filename", ucv_string_new(source->filename));
983                         ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(source, &srcpos)));
984                         ucv_object_add(entry, "byte", ucv_int64_new(srcpos));
985                 }
986 
987                 if (i > 1) {
988                         if (frame->closure) {
989                                 if (frame->closure->function->name[0])
990                                         name = frame->closure->function->name;
991                                 else if (frame->closure->is_arrow)
992                                         name = "[arrow function]";
993                                 else
994                                         name = "[anonymous function]";
995                         }
996                         else {
997                                 name = frame->cfunction->name;
998                         }
999 
1000                         ucv_object_add(entry, "function", ucv_string_new(name));
1001                 }
1002 
1003                 if (!ucv_is_equal(last, entry)) {
1004                         ucv_array_push(stacktrace, entry);
1005                         last = entry;
1006                 }
1007                 else {
1008                         ucv_put(entry);
1009                 }
1010         }
1011 
1012         return stacktrace;
1013 }
1014 
1015 static uc_value_t *
1016 uc_vm_get_error_context(uc_vm_t *vm)
1017 {
1018         size_t offset, i, byte, line;
1019         uc_value_t *stacktrace;
1020         uc_callframe_t *frame;
1021         uc_stringbuf_t *buf;
1022         uc_chunk_t *chunk;
1023 
1024         if (vm->callframes.count == 0)
1025                 return NULL;
1026 
1027         /* skip to first non-native function call frame */
1028         for (i = vm->callframes.count; i > 1; i--)
1029                 if (vm->callframes.entries[i - 1].closure)
1030                         break;
1031 
1032         frame = &vm->callframes.entries[i - 1];
1033 
1034         if (!frame->closure)
1035                 return NULL;
1036 
1037         chunk = uc_vm_frame_chunk(frame);
1038         offset = uc_program_function_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1);
1039         stacktrace = uc_vm_capture_stacktrace(vm, i);
1040 
1041         buf = ucv_stringbuf_new();
1042 
1043         byte = offset;
1044         line = uc_source_get_line(uc_program_function_source(frame->closure->function), &byte);
1045 
1046         if (line)
1047                 uc_error_context_format(buf, uc_vm_frame_source(frame), stacktrace, offset);
1048         else if (frame->ip != chunk->entries)
1049                 ucv_stringbuf_printf(buf, "At instruction %zu", (frame->ip - chunk->entries) - 1);
1050         else
1051                 ucv_stringbuf_append(buf, "At start of program");
1052 
1053         ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf));
1054 
1055         return stacktrace;
1056 }
1057 
1058 void __attribute__((format(printf, 3, 0)))
1059 uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...)
1060 {
1061         va_list ap;
1062 
1063         vm->exception.type = type;
1064 
1065         free(vm->exception.message);
1066 
1067         va_start(ap, fmt);
1068         xvasprintf(&vm->exception.message, fmt, ap);
1069         va_end(ap);
1070 
1071         ucv_put(vm->exception.stacktrace);
1072         vm->exception.stacktrace = uc_vm_get_error_context(vm);
1073 }
1074 
1075 static bool
1076 uc_vm_test_strict_equality(uc_value_t *v1, uc_value_t *v2, bool nan_equal)
1077 {
1078         uc_type_t t1 = ucv_type(v1);
1079         uc_type_t t2 = ucv_type(v2);
1080         double d1, d2;
1081 
1082         if (t1 != t2)
1083                 return false;
1084 
1085         switch (t1) {
1086         case UC_DOUBLE:
1087                 d1 = ((uc_double_t *)v1)->dbl;
1088                 d2 = ((uc_double_t *)v2)->dbl;
1089 
1090                 if (isnan(d1) && isnan(d2))
1091                         return nan_equal;
1092 
1093                 return (d1 == d2);
1094 
1095         case UC_NULL:
1096         case UC_BOOLEAN:
1097         case UC_INTEGER:
1098         case UC_STRING:
1099                 return ucv_is_equal(v1, v2);
1100 
1101         default:
1102                 return (v1 == v2);
1103         }
1104 }
1105 
1106 
1107 static void
1108 uc_vm_insn_load(uc_vm_t *vm, uc_vm_insn_t insn)
1109 {
1110         switch (insn) {
1111         case I_LOAD:
1112                 uc_vm_stack_push(vm, uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32));
1113                 break;
1114 
1115         case I_LOAD8:
1116                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u8));
1117                 break;
1118 
1119         case I_LOAD16:
1120                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u16));
1121                 break;
1122 
1123         case I_LOAD32:
1124                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u32));
1125                 break;
1126 
1127         default:
1128                 break;
1129         }
1130 }
1131 
1132 static void
1133 uc_vm_insn_load_regexp(uc_vm_t *vm, uc_vm_insn_t insn)
1134 {
1135         uc_value_t *re, *jstr = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
1136         bool icase = false, newline = false, global = false;
1137         char *str, *err = NULL;
1138 
1139         if (ucv_type(jstr) != UC_STRING || ucv_string_length(jstr) < 2) {
1140                 uc_vm_stack_push(vm, NULL);
1141                 ucv_put(jstr);
1142 
1143                 return;
1144         }
1145 
1146         str = ucv_string_get(jstr);
1147 
1148         global  = (*str & (1 << 0));
1149         icase   = (*str & (1 << 1));
1150         newline = (*str & (1 << 2));
1151 
1152         re = ucv_regexp_new(++str, icase, newline, global, &err);
1153 
1154         ucv_put(jstr);
1155 
1156         if (re)
1157                 uc_vm_stack_push(vm, re);
1158         else
1159                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err);
1160 
1161         free(err);
1162 }
1163 
1164 static void
1165 uc_vm_insn_load_null(uc_vm_t *vm, uc_vm_insn_t insn)
1166 {
1167         uc_vm_stack_push(vm, NULL);
1168 }
1169 
1170 static void
1171 uc_vm_insn_load_bool(uc_vm_t *vm, uc_vm_insn_t insn)
1172 {
1173         uc_vm_stack_push(vm, ucv_boolean_new(insn == I_LTRUE));
1174 }
1175 
1176 static void
1177 uc_vm_insn_load_var(uc_vm_t *vm, uc_vm_insn_t insn)
1178 {
1179         uc_value_t *name, *val = NULL;
1180         uc_value_t *scope, *next;
1181         bool found;
1182 
1183         scope = vm->globals;
1184         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
1185 
1186         while (ucv_type(name) == UC_STRING) {
1187                 val = ucv_object_get(scope, ucv_string_get(name), &found);
1188 
1189                 if (found)
1190                         break;
1191 
1192                 next = ucv_prototype_get(scope);
1193 
1194                 if (!next) {
1195                         if (uc_vm_is_strict(vm)) {
1196                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1197                                                       "access to undeclared variable %s",
1198                                                       ucv_string_get(name));
1199                         }
1200 
1201                         break;
1202                 }
1203 
1204                 scope = next;
1205         }
1206 
1207         ucv_put(name);
1208 
1209         uc_vm_stack_push(vm, ucv_get(val));
1210 }
1211 
1212 static void
1213 uc_vm_insn_load_val(uc_vm_t *vm, uc_vm_insn_t insn)
1214 {
1215         uc_value_t *k = uc_vm_stack_pop(vm);
1216         uc_value_t *v = uc_vm_stack_pop(vm);
1217 
1218         switch (ucv_type(v)) {
1219         case UC_RESOURCE:
1220         case UC_OBJECT:
1221         case UC_ARRAY:
1222                 uc_vm_stack_push(vm, ucv_key_get(vm, v, k));
1223                 break;
1224 
1225         default:
1226                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1227                                       "left-hand side expression is %s",
1228                                       v ? "not an array or object" : "null");
1229 
1230                 break;
1231         }
1232 
1233         ucv_put(k);
1234         ucv_put(v);
1235 }
1236 
1237 static void
1238 uc_vm_insn_peek_val(uc_vm_t *vm, uc_vm_insn_t insn)
1239 {
1240         uc_value_t *k = uc_vm_stack_pop(vm);
1241         uc_value_t *v = uc_vm_stack_peek(vm, 0);
1242 
1243         switch (ucv_type(v)) {
1244         case UC_RESOURCE:
1245         case UC_OBJECT:
1246         case UC_ARRAY:
1247                 uc_vm_stack_push(vm, ucv_key_get(vm, v, k));
1248                 break;
1249 
1250         default:
1251                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1252                                                                 "left-hand side expression is %s",
1253                                                                 v ? "not an array or object" : "null");
1254 
1255                 break;
1256         }
1257 
1258         ucv_put(k);
1259 }
1260 
1261 static void
1262 uc_vm_insn_load_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1263 {
1264         uc_callframe_t *frame = uc_vm_current_frame(vm);
1265         uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32];
1266 
1267         if (ref->closed)
1268                 uc_vm_stack_push(vm, ucv_get(ref->value));
1269         else
1270                 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[ref->slot]));
1271 }
1272 
1273 static void
1274 uc_vm_insn_load_local(uc_vm_t *vm, uc_vm_insn_t insn)
1275 {
1276         uc_callframe_t *frame = uc_vm_current_frame(vm);
1277 
1278         uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32]));
1279 }
1280 
1281 static uc_upvalref_t *
1282 uc_vm_capture_upval(uc_vm_t *vm, size_t slot)
1283 {
1284         uc_upvalref_t *curr = vm->open_upvals;
1285         uc_upvalref_t *prev = NULL;
1286         uc_upvalref_t *created;
1287         char *s;
1288 
1289         while (curr && curr->slot > slot) {
1290                 prev = curr;
1291                 curr = curr->next;
1292         }
1293 
1294         if (curr && curr->slot == slot) {
1295                 if (vm->trace) {
1296                         s = ucv_to_string(NULL, vm->stack.entries[slot]);
1297                         fprintf(stderr, "  {+%zu} <%p> %s\n", slot, (void *)curr, s);
1298                         free(s);
1299                 }
1300 
1301                 return curr;
1302         }
1303 
1304         created = (uc_upvalref_t *)ucv_upvalref_new(slot);
1305         created->next = curr;
1306 
1307         if (vm->trace) {
1308                 s = ucv_to_string(NULL, vm->stack.entries[slot]);
1309                 fprintf(stderr, "  {*%zu} <%p> %s\n", slot, (void *)created, s);
1310                 free(s);
1311         }
1312 
1313         if (prev)
1314                 prev->next = created;
1315         else
1316                 vm->open_upvals = created;
1317 
1318         return created;
1319 }
1320 
1321 static void
1322 uc_vm_close_upvals(uc_vm_t *vm, size_t slot)
1323 {
1324         uc_upvalref_t *ref;
1325 
1326         while (vm->open_upvals && vm->open_upvals->slot >= slot) {
1327                 ref = vm->open_upvals;
1328                 ref->value = ucv_get(vm->stack.entries[ref->slot]);
1329                 ref->closed = true;
1330 
1331                 if (vm->trace) {
1332                         fprintf(stderr, "  {!%zu} <%p> %s\n", ref->slot,
1333                                 (void *)ref,
1334                                 uc_vm_format_val(vm, ref->value));
1335                 }
1336 
1337                 vm->open_upvals = ref->next;
1338                 ucv_put(&ref->header);
1339         }
1340 }
1341 
1342 static void
1343 uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn)
1344 {
1345         uc_callframe_t *frame = uc_vm_current_frame(vm);
1346         uc_function_t *function = uc_program_function_load(uc_vm_current_program(vm), vm->arg.u32);
1347         uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN);
1348         volatile int32_t uv;
1349         size_t i;
1350 
1351         uc_vm_stack_push(vm, &closure->header);
1352 
1353         if (function->module)
1354                 return;
1355 
1356         for (i = 0; i < function->nupvals; i++) {
1357                 uv = (
1358                         frame->ip[0] * 0x1000000 +
1359                         frame->ip[1] * 0x10000 +
1360                         frame->ip[2] * 0x100 +
1361                         frame->ip[3]
1362                 ) - 0x7fffffff;
1363 
1364                 if (uv < 0)
1365                         closure->upvals[i] = uc_vm_capture_upval(vm, frame->stackframe - (uv + 1));
1366                 else
1367                         closure->upvals[i] = frame->closure->upvals[uv];
1368 
1369                 ucv_get(&closure->upvals[i]->header);
1370 
1371                 frame->ip += 4;
1372         }
1373 }
1374 
1375 static void
1376 uc_vm_insn_store_var(uc_vm_t *vm, uc_vm_insn_t insn)
1377 {
1378         uc_value_t *name, *v = uc_vm_stack_pop(vm);
1379         uc_value_t *scope, *next;
1380         bool found;
1381 
1382         scope = vm->globals;
1383         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
1384 
1385         while (ucv_type(name) == UC_STRING) {
1386                 ucv_object_get(scope, ucv_string_get(name), &found);
1387 
1388                 if (found)
1389                         break;
1390 
1391                 next = ucv_prototype_get(scope);
1392 
1393                 if (!next) {
1394                         if (uc_vm_is_strict(vm)) {
1395                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1396                                                       "access to undeclared variable %s",
1397                                                       ucv_string_get(name));
1398                                 ucv_put(name);
1399                                 ucv_put(v);
1400 
1401                                 return;
1402                         }
1403 
1404                         break;
1405                 }
1406 
1407                 scope = next;
1408         }
1409 
1410         if (scope && ucv_type(name) == UC_STRING)
1411                 ucv_object_add(scope, ucv_string_get(name), ucv_get(v));
1412 
1413         ucv_put(name);
1414         uc_vm_stack_push(vm, v);
1415 }
1416 
1417 static bool
1418 assert_mutable_value(uc_vm_t *vm, uc_value_t *val)
1419 {
1420         if (ucv_is_constant(val)) {
1421                 uc_vm_stack_push(vm, NULL);
1422                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1423                                       "%s value is immutable",
1424                                       ucv_typename(val));
1425 
1426                 return false;
1427         }
1428 
1429         return true;
1430 }
1431 
1432 static void
1433 uc_vm_insn_store_val(uc_vm_t *vm, uc_vm_insn_t insn)
1434 {
1435         uc_value_t *v = uc_vm_stack_pop(vm);
1436         uc_value_t *k = uc_vm_stack_pop(vm);
1437         uc_value_t *o = uc_vm_stack_pop(vm);
1438 
1439         switch (ucv_type(o)) {
1440         case UC_OBJECT:
1441         case UC_ARRAY:
1442                 if (assert_mutable_value(vm, o)) {
1443                         uc_value_t *rv = ucv_key_set(vm, o, k, v);
1444 
1445                         /* on success rv is a reference to the stored value that gets
1446                          * pushed onto the stack; clear v so the cleanup below does not
1447                          * release the reference now owned by the stack */
1448                         if (rv)
1449                                 v = NULL;
1450 
1451                         uc_vm_stack_push(vm, rv);
1452                 }
1453 
1454                 break;
1455 
1456         default:
1457                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1458                                       "attempt to set property on %s value",
1459                                       ucv_typename(o));
1460         }
1461 
1462         ucv_put(v);
1463         ucv_put(o);
1464         ucv_put(k);
1465 }
1466 
1467 static void
1468 uc_vm_insn_store_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1469 {
1470         uc_callframe_t *frame = uc_vm_current_frame(vm);
1471         uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32];
1472         uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0));
1473 
1474         if (ref->closed) {
1475                 ucv_put(ref->value);
1476                 ref->value = val;
1477         }
1478         else {
1479                 uc_vm_stack_set(vm, ref->slot, val);
1480         }
1481 }
1482 
1483 static void
1484 uc_vm_insn_store_local(uc_vm_t *vm, uc_vm_insn_t insn)
1485 {
1486         uc_callframe_t *frame = uc_vm_current_frame(vm);
1487         uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0));
1488 
1489         uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val);
1490 }
1491 
1492 static int64_t
1493 int64(uc_value_t *nv, uint64_t *u64)
1494 {
1495         int64_t n;
1496 
1497         n = ucv_int64_get(nv);
1498         *u64 = 0;
1499 
1500         if (errno == ERANGE) {
1501                 n = INT64_MAX;
1502                 *u64 = ucv_uint64_get(nv);
1503         }
1504 
1505         return n;
1506 }
1507 
1508 static uint64_t
1509 abs64(int64_t n)
1510 {
1511         if (n == INT64_MIN)
1512                 return 0x8000000000000000ULL;
1513 
1514         if (n < 0)
1515                 return -n;
1516 
1517         return n;
1518 }
1519 
1520 
1521 static uc_value_t *
1522 uc_vm_value_bitop(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand)
1523 {
1524         uc_value_t *nv1, *nv2, *rv = NULL;
1525         uint64_t u1, u2;
1526         int64_t n1, n2;
1527 
1528         nv1 = ucv_to_number(value);
1529         nv2 = ucv_to_number(operand);
1530 
1531         n1 = int64(nv1, &u1);
1532         n2 = int64(nv2, &u2);
1533 
1534         if (n1 < 0 || n2 < 0) {
1535                 switch (operation) {
1536                 case I_LSHIFT:
1537                         rv = ucv_int64_new(n1 << n2);
1538                         break;
1539 
1540                 case I_RSHIFT:
1541                         rv = ucv_int64_new(n1 >> n2);
1542                         break;
1543 
1544                 case I_BAND:
1545                         rv = ucv_int64_new(n1 & n2);
1546                         break;
1547 
1548                 case I_BXOR:
1549                         rv = ucv_int64_new(n1 ^ n2);
1550                         break;
1551 
1552                 case I_BOR:
1553                         rv = ucv_int64_new(n1 | n2);
1554                         break;
1555 
1556                 default:
1557                         break;
1558                 }
1559         }
1560         else {
1561                 if (!u1) u1 = (uint64_t)n1;
1562                 if (!u2) u2 = (uint64_t)n2;
1563 
1564                 switch (operation) {
1565                 case I_LSHIFT:
1566                         rv = ucv_uint64_new(u1 << (u2 % (sizeof(uint64_t) * CHAR_BIT)));
1567                         break;
1568 
1569                 case I_RSHIFT:
1570                         rv = ucv_uint64_new(u1 >> (u2 % (sizeof(uint64_t) * CHAR_BIT)));
1571                         break;
1572 
1573                 case I_BAND:
1574                         rv = ucv_uint64_new(u1 & u2);
1575                         break;
1576 
1577                 case I_BXOR:
1578                         rv = ucv_uint64_new(u1 ^ u2);
1579                         break;
1580 
1581                 case I_BOR:
1582                         rv = ucv_uint64_new(u1 | u2);
1583                         break;
1584 
1585                 default:
1586                         break;
1587                 }
1588         }
1589 
1590         ucv_put(nv1);
1591         ucv_put(nv2);
1592 
1593         return rv;
1594 }
1595 
1596 static uc_value_t *
1597 uc_vm_string_concat(uc_vm_t *vm, uc_value_t *v1, uc_value_t *v2)
1598 {
1599         char buf[sizeof(void *)], *s1, *s2, *str;
1600         uc_value_t *ustr;
1601         uc_stringbuf_t *sbuf;
1602         size_t l1, l2;
1603 
1604         /* optimize cases for string+string concat... */
1605         if (ucv_type(v1) == UC_STRING && ucv_type(v2) == UC_STRING) {
1606                 s1 = ucv_string_get(v1);
1607                 s2 = ucv_string_get(v2);
1608                 l1 = ucv_string_length(v1);
1609                 l2 = ucv_string_length(v2);
1610 
1611                 /* ... result fits into a tagged pointer */
1612                 if (l1 + l2 + 1 < sizeof(buf)) {
1613                         memcpy(&buf[0], s1, l1);
1614                         memcpy(&buf[l1], s2, l2);
1615 
1616                         return ucv_string_new_length(buf, l1 + l2);
1617                 }
1618                 else {
1619                         ustr = ucv_string_alloc(&str, l1 + l2);
1620                         memcpy(&str[0], s1, l1);
1621                         memcpy(&str[l1], s2, l2);
1622 
1623                         return ustr;
1624                 }
1625         }
1626 
1627         sbuf = ucv_stringbuf_new();
1628 
1629         ucv_to_stringbuf(vm, sbuf, v1, false);
1630         ucv_to_stringbuf(vm, sbuf, v2, false);
1631 
1632         return ucv_stringbuf_finish(sbuf);
1633 }
1634 
1635 static uint64_t
1636 upow64(uint64_t base, uint64_t exponent)
1637 {
1638         uint64_t result = 1;
1639 
1640         while (exponent) {
1641                 if (exponent & 1)
1642                         result *= base;
1643 
1644                 exponent >>= 1;
1645                 base *= base;
1646         }
1647 
1648         return result;
1649 }
1650 
1651 static uc_value_t *
1652 uc_vm_value_arith(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand)
1653 {
1654         uc_value_t *nv1, *nv2, *rv = NULL;
1655         uint64_t u1, u2;
1656         int64_t n1, n2;
1657         double d1, d2;
1658 
1659         if (operation == I_LSHIFT || operation == I_RSHIFT ||
1660             operation == I_BAND || operation == I_BXOR || operation == I_BOR)
1661                 return uc_vm_value_bitop(vm, operation, value, operand);
1662 
1663         if (operation == I_ADD && (ucv_type(value) == UC_STRING || ucv_type(operand) == UC_STRING))
1664                 return uc_vm_string_concat(vm, value, operand);
1665 
1666         nv1 = ucv_to_number(value);
1667         nv2 = ucv_to_number(operand);
1668 
1669         /* any operation involving NaN results in NaN */
1670         if (!nv1 || !nv2) {
1671                 ucv_put(nv1);
1672                 ucv_put(nv2);
1673 
1674                 return ucv_double_new(NAN);
1675         }
1676         if (ucv_type(nv1) == UC_DOUBLE || ucv_type(nv2) == UC_DOUBLE) {
1677                 d1 = ucv_double_get(nv1);
1678                 d2 = ucv_double_get(nv2);
1679 
1680                 switch (operation) {
1681                 case I_ADD:
1682                 case I_PLUS:
1683                         rv = ucv_double_new(d1 + d2);
1684                         break;
1685 
1686                 case I_SUB:
1687                 case I_MINUS:
1688                         rv = ucv_double_new(d1 - d2);
1689                         break;
1690 
1691                 case I_MUL:
1692                         rv = ucv_double_new(d1 * d2);
1693                         break;
1694 
1695                 case I_DIV:
1696                         if (d2 == 0.0)
1697                                 rv = ucv_double_new(INFINITY);
1698                         else if (isnan(d2))
1699                                 rv = ucv_double_new(NAN);
1700                         else if (!isfinite(d2))
1701                                 rv = ucv_double_new(isfinite(d1) ? 0.0 : NAN);
1702                         else
1703                                 rv = ucv_double_new(d1 / d2);
1704 
1705                         break;
1706 
1707                 case I_MOD:
1708                         rv = ucv_double_new(fmod(d1, d2));
1709                         break;
1710 
1711                 case I_EXP:
1712                         rv = ucv_double_new(pow(d1, d2));
1713                         break;
1714 
1715                 default:
1716                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1717                                               "undefined arithmetic operation %d",
1718                                               operation);
1719                         break;
1720                 }
1721         }
1722         else {
1723                 n1 = int64(nv1, &u1);
1724                 n2 = int64(nv2, &u2);
1725 
1726                 switch (operation) {
1727                 case I_ADD:
1728                 case I_PLUS:
1729                         if (n1 < 0 || n2 < 0) {
1730                                 if (u1)
1731                                         rv = ucv_uint64_new(u1 - abs64(n2));
1732                                 else if (u2)
1733                                         rv = ucv_uint64_new(u2 - abs64(n1));
1734                                 else
1735                                         rv = ucv_int64_new(n1 + n2);
1736                         }
1737                         else {
1738                                 if (!u1) u1 = (uint64_t)n1;
1739                                 if (!u2) u2 = (uint64_t)n2;
1740 
1741                                 rv = ucv_uint64_new(u1 + u2);
1742                         }
1743 
1744                         break;
1745 
1746                 case I_SUB:
1747                 case I_MINUS:
1748                         if (n1 < 0 && n2 < 0) {
1749                                 if (n1 > n2)
1750                                         rv = ucv_uint64_new(abs64(n2) - abs64(n1));
1751                                 else
1752                                         rv = ucv_int64_new(n1 - n2);
1753                         }
1754                         else if (n1 >= 0 && n2 >= 0) {
1755                                 if (!u1) u1 = (uint64_t)n1;
1756                                 if (!u2) u2 = (uint64_t)n2;
1757 
1758                                 if (u2 > u1)
1759                                         rv = ucv_int64_new(-(u2 - u1));
1760                                 else
1761                                         rv = ucv_uint64_new(u1 - u2);
1762                         }
1763                         else if (n1 >= 0) {
1764                                 if (!u1) u1 = (uint64_t)n1;
1765 
1766                                 rv = ucv_uint64_new(u1 + abs64(n2));
1767                         }
1768                         else {
1769                                 rv = ucv_int64_new(n1 - n2);
1770                         }
1771 
1772                         break;
1773 
1774                 case I_MUL:
1775                         if (n1 < 0 && n2 < 0) {
1776                                 rv = ucv_uint64_new(abs64(n1) * abs64(n2));
1777                         }
1778                         else if (n1 >= 0 && n2 >= 0) {
1779                                 if (!u1) u1 = (uint64_t)n1;
1780                                 if (!u2) u2 = (uint64_t)n2;
1781 
1782                                 rv = ucv_uint64_new(u1 * u2);
1783                         }
1784                         else {
1785                                 rv = ucv_int64_new(n1 * n2);
1786                         }
1787 
1788                         break;
1789 
1790                 case I_DIV:
1791                         if (n2 == 0) {
1792                                 rv = ucv_double_new(INFINITY);
1793                         }
1794                         else if (n1 == INT64_MIN && n2 == -1) {
1795                                 /* the mathematical result 2^63 only fits into uint64_t;
1796                                  * the signed division would trap with SIGFPE */
1797                                 rv = ucv_uint64_new((uint64_t)INT64_MAX + 1);
1798                         }
1799                         else if (n1 < 0 || n2 < 0) {
1800                                 rv = ucv_int64_new(n1 / n2);
1801                         }
1802                         else {
1803                                 if (!u1) u1 = (uint64_t)n1;
1804                                 if (!u2) u2 = (uint64_t)n2;
1805 
1806                                 rv = ucv_uint64_new(u1 / u2);
1807                         }
1808 
1809                         break;
1810 
1811                 case I_MOD:
1812                         if (n2 == 0) {
1813                                 rv = ucv_double_new(NAN);
1814                         }
1815                         else if (n1 == INT64_MIN && n2 == -1) {
1816                                 /* the signed modulo would trap with SIGFPE */
1817                                 rv = ucv_int64_new(0);
1818                         }
1819                         else if (n1 < 0 || n2 < 0) {
1820                                 rv = ucv_int64_new(n1 % n2);
1821                         }
1822                         else {
1823                                 if (!u1) u1 = (uint64_t)n1;
1824                                 if (!u2) u2 = (uint64_t)n2;
1825 
1826                                 rv = ucv_uint64_new(u1 % u2);
1827                         }
1828 
1829                         break;
1830 
1831                 case I_EXP:
1832                         if (n1 < 0 || n2 < 0) {
1833                                 /* the result is negative iff the base is negative and the
1834                                  * exponent is odd */
1835                                 if (n2 < 0)
1836                                         rv = ucv_double_new(((n1 < 0 && (n2 & 1)) ? -1.0 : 1.0) /
1837                                                 (double)upow64(abs64(n1), abs64(n2)));
1838                                 else if (n2 & 1)
1839                                         rv = ucv_int64_new((int64_t)-upow64(abs64(n1), abs64(n2)));
1840                                 else
1841                                         rv = ucv_uint64_new(upow64(abs64(n1), abs64(n2)));
1842                         }
1843                         else {
1844                                 if (!u1) u1 = (uint64_t)n1;
1845                                 if (!u2) u2 = (uint64_t)n2;
1846 
1847                                 rv = ucv_uint64_new(upow64(u1, u2));
1848                         }
1849 
1850                         break;
1851 
1852                 default:
1853                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1854                                               "undefined arithmetic operation %d",
1855                                               operation);
1856                         break;
1857                 }
1858         }
1859 
1860         ucv_put(nv1);
1861         ucv_put(nv2);
1862 
1863         return rv;
1864 }
1865 
1866 static void
1867 uc_vm_insn_update_var(uc_vm_t *vm, uc_vm_insn_t insn)
1868 {
1869         uc_value_t *name, *val = NULL, *inc = uc_vm_stack_pop(vm);
1870         uc_value_t *scope, *next;
1871         bool found;
1872 
1873         scope = vm->globals;
1874         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32 & 0x00FFFFFF);
1875 
1876         assert(ucv_type(name) == UC_STRING);
1877 
1878         while (true) {
1879                 val = ucv_object_get(scope, ucv_string_get(name), &found);
1880 
1881                 if (found)
1882                         break;
1883 
1884                 next = ucv_prototype_get(scope);
1885 
1886                 if (!next) {
1887                         if (uc_vm_is_strict(vm)) {
1888                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1889                                                       "access to undeclared variable %s",
1890                                                       ucv_string_get(name));
1891                                 ucv_put(name);
1892                                 ucv_put(inc);
1893 
1894                                 return;
1895                         }
1896 
1897                         break;
1898                 }
1899 
1900                 scope = next;
1901         }
1902 
1903         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc);
1904 
1905         ucv_object_add(scope, ucv_string_get(name), ucv_get(val));
1906         uc_vm_stack_push(vm, val);
1907 
1908         ucv_put(name);
1909         ucv_put(inc);
1910 }
1911 
1912 static void
1913 uc_vm_insn_update_val(uc_vm_t *vm, uc_vm_insn_t insn)
1914 {
1915         uc_value_t *inc = uc_vm_stack_pop(vm);
1916         uc_value_t *k = uc_vm_stack_pop(vm);
1917         uc_value_t *v = uc_vm_stack_pop(vm);
1918         uc_value_t *val = NULL;
1919 
1920         switch (ucv_type(v)) {
1921         case UC_OBJECT:
1922         case UC_ARRAY:
1923                 if (assert_mutable_value(vm, v)) {
1924                         uc_value_t *nv, *rv;
1925 
1926                         val = ucv_key_get(vm, v, k);
1927                         nv = uc_vm_value_arith(vm, vm->arg.u8, val, inc);
1928                         rv = ucv_key_set(vm, v, k, nv);
1929 
1930                         /* on success rv is a reference to the stored value that gets
1931                          * pushed onto the stack; on failure nv was not stored, so
1932                          * release it here */
1933                         if (!rv)
1934                                 ucv_put(nv);
1935 
1936                         uc_vm_stack_push(vm, rv);
1937                 }
1938 
1939                 break;
1940 
1941         default:
1942                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1943                                       "left-hand side expression is %s",
1944                                       v ? "not an array or object" : "null");
1945 
1946                 break;
1947         }
1948 
1949         ucv_put(val);
1950         ucv_put(inc);
1951         ucv_put(v);
1952         ucv_put(k);
1953 }
1954 
1955 static void
1956 uc_vm_insn_update_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1957 {
1958         uc_callframe_t *frame = uc_vm_current_frame(vm);
1959         size_t slot = vm->arg.u32 & 0x00FFFFFF;
1960         uc_upvalref_t *ref = frame->closure->upvals[slot];
1961         uc_value_t *inc = uc_vm_stack_pop(vm);
1962         uc_value_t *val;
1963 
1964         if (ref->closed)
1965                 val = ref->value;
1966         else
1967                 val = vm->stack.entries[ref->slot];
1968 
1969         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc);
1970 
1971         uc_vm_stack_push(vm, val);
1972 
1973         ucv_put(inc);
1974 
1975         if (ref->closed) {
1976                 ucv_put(ref->value);
1977                 ref->value = ucv_get(uc_vm_stack_peek(vm, 0));
1978         }
1979         else {
1980                 uc_vm_stack_set(vm, ref->slot, ucv_get(uc_vm_stack_peek(vm, 0)));
1981         }
1982 }
1983 
1984 static void
1985 uc_vm_insn_update_local(uc_vm_t *vm, uc_vm_insn_t insn)
1986 {
1987         uc_callframe_t *frame = uc_vm_current_frame(vm);
1988         size_t slot = vm->arg.u32 & 0x00FFFFFF;
1989         uc_value_t *inc = uc_vm_stack_pop(vm);
1990         uc_value_t *val;
1991 
1992         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24,
1993                                 vm->stack.entries[frame->stackframe + slot], inc);
1994 
1995         uc_vm_stack_push(vm, val);
1996 
1997         ucv_put(inc);
1998         uc_vm_stack_set(vm, frame->stackframe + slot, ucv_get(uc_vm_stack_peek(vm, 0)));
1999 }
2000 
2001 static void
2002 uc_vm_insn_narr(uc_vm_t *vm, uc_vm_insn_t insn)
2003 {
2004         uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32);
2005 
2006         uc_vm_stack_push(vm, arr);
2007 }
2008 
2009 static void
2010 uc_vm_insn_parr(uc_vm_t *vm, uc_vm_insn_t insn)
2011 {
2012         uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32);
2013         size_t idx;
2014 
2015         for (idx = 0; idx < vm->arg.u32; idx++)
2016                 ucv_array_push(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1));
2017 
2018         for (idx = 0; idx < vm->arg.u32; idx++)
2019                 uc_vm_stack_pop(vm);
2020 
2021         //uc_vm_shrink(state, vm->arg.u32);
2022 }
2023 
2024 static void
2025 uc_vm_insn_marr(uc_vm_t *vm, uc_vm_insn_t insn)
2026 {
2027         uc_value_t *src = uc_vm_stack_pop(vm);
2028         uc_value_t *dst = uc_vm_stack_peek(vm, 0);
2029         size_t i;
2030         char *s;
2031 
2032         if (ucv_type(src) != UC_ARRAY) {
2033                 s = ucv_to_string(vm, src);
2034                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s);
2035                 ucv_put(src);
2036                 free(s);
2037 
2038                 return;
2039         }
2040 
2041         for (i = 0; i < ucv_array_length(src); i++)
2042                 ucv_array_push(dst, ucv_get(ucv_array_get(src, i)));
2043 
2044         ucv_put(src);
2045 }
2046 
2047 static void
2048 uc_vm_insn_nobj(uc_vm_t *vm, uc_vm_insn_t insn)
2049 {
2050         uc_value_t *obj = ucv_object_new(vm);
2051 
2052         uc_vm_stack_push(vm, obj);
2053 }
2054 
2055 static void
2056 uc_vm_insn_sobj(uc_vm_t *vm, uc_vm_insn_t insn)
2057 {
2058         uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32);
2059         size_t idx;
2060 
2061         for (idx = 0; idx < vm->arg.u32; idx += 2)
2062                 ucv_key_set(vm, obj,
2063                         uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1),
2064                         uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2));
2065 
2066         for (idx = 0; idx < vm->arg.u32; idx++)
2067                 ucv_put(uc_vm_stack_pop(vm));
2068 }
2069 
2070 static void
2071 uc_vm_insn_mobj(uc_vm_t *vm, uc_vm_insn_t insn)
2072 {
2073         uc_value_t *src = uc_vm_stack_pop(vm);
2074         uc_value_t *dst = uc_vm_stack_peek(vm, 0);
2075         size_t i;
2076         char *s;
2077 
2078         switch (ucv_type(src)) {
2079         case UC_OBJECT:
2080                 ; /* a label can only be part of a statement and a declaration is not a statement */
2081                 ucv_object_foreach(src, k, v)
2082                         ucv_object_add(dst, k, ucv_get(v));
2083 
2084                 ucv_put(src);
2085                 break;
2086 
2087         case UC_ARRAY:
2088                 for (i = 0; i < ucv_array_length(src); i++) {
2089                         xasprintf(&s, "%zu", i);
2090                         ucv_object_add(dst, s, ucv_get(ucv_array_get(src, i)));
2091                         free(s);
2092                 }
2093 
2094                 ucv_put(src);
2095                 break;
2096 
2097         default:
2098                 s = ucv_to_string(vm, src);
2099                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Value (%s) is not iterable", s);
2100                 free(s);
2101 
2102                 break;
2103         }
2104 }
2105 
2106 static void
2107 uc_vm_insn_arith(uc_vm_t *vm, uc_vm_insn_t insn)
2108 {
2109         uc_value_t *r2 = uc_vm_stack_pop(vm);
2110         uc_value_t *r1 = uc_vm_stack_pop(vm);
2111         uc_value_t *rv;
2112 
2113         rv = uc_vm_value_arith(vm, insn, r1, r2);
2114 
2115         ucv_put(r1);
2116         ucv_put(r2);
2117 
2118         uc_vm_stack_push(vm, rv);
2119 }
2120 
2121 static void
2122 uc_vm_insn_plus_minus(uc_vm_t *vm, uc_vm_insn_t insn)
2123 {
2124         uc_value_t *v = uc_vm_stack_pop(vm), *nv;
2125         bool is_sub = (insn == I_MINUS);
2126         int64_t n;
2127         double d;
2128 
2129         if (ucv_type(v) == UC_STRING) {
2130                 nv = uc_number_parse(ucv_string_get(v), NULL);
2131 
2132                 if (nv) {
2133                         ucv_put(v);
2134                         v = nv;
2135                 }
2136         }
2137 
2138         switch (ucv_type(v)) {
2139         case UC_INTEGER:
2140                 n = ucv_int64_get(v);
2141 
2142                 /* numeric value is in range 9223372036854775808..18446744073709551615 */
2143                 if (errno == ERANGE) {
2144                         if (is_sub)
2145                                 /* make negation of large numeric value result in smallest negative value */
2146                                 uc_vm_stack_push(vm, ucv_int64_new(INT64_MIN));
2147                         else
2148                                 /* for positive number coercion return value as-is */
2149                                 uc_vm_stack_push(vm, ucv_get(v));
2150                 }
2151 
2152                 /* numeric value is in range -9223372036854775808..9223372036854775807 */
2153                 else {
2154                         if (is_sub) {
2155                                 if (n == INT64_MIN)
2156                                         /* make negation of minimum value result in maximum signed positive value */
2157                                         uc_vm_stack_push(vm, ucv_int64_new(INT64_MAX));
2158                                 else
2159                                         /* for all other values flip the sign */
2160                                         uc_vm_stack_push(vm, ucv_int64_new(-n));
2161                         }
2162                         else {
2163                                 /* for positive number coercion return value as-is */
2164                                 uc_vm_stack_push(vm, ucv_get(v));
2165                         }
2166                 }
2167 
2168                 break;
2169 
2170         case UC_DOUBLE:
2171                 d = ucv_double_get(v);
2172                 uc_vm_stack_push(vm, ucv_double_new(is_sub ? -d : d));
2173                 break;
2174 
2175         case UC_BOOLEAN:
2176                 n = (int64_t)ucv_boolean_get(v);
2177                 uc_vm_stack_push(vm, ucv_int64_new(is_sub ? -n : n));
2178                 break;
2179 
2180         case UC_NULL:
2181                 uc_vm_stack_push(vm, ucv_int64_new(0));
2182                 break;
2183 
2184         default:
2185                 uc_vm_stack_push(vm, ucv_double_new(NAN));
2186         }
2187 
2188         ucv_put(v);
2189 }
2190 
2191 static void
2192 uc_vm_insn_bitop(uc_vm_t *vm, uc_vm_insn_t insn)
2193 {
2194         uc_value_t *r2 = uc_vm_stack_pop(vm);
2195         uc_value_t *r1 = uc_vm_stack_pop(vm);
2196         uc_value_t *rv;
2197 
2198         rv = uc_vm_value_bitop(vm, insn, r1, r2);
2199 
2200         ucv_put(r1);
2201         ucv_put(r2);
2202 
2203         uc_vm_stack_push(vm, rv);
2204 }
2205 
2206 static void
2207 uc_vm_insn_complement(uc_vm_t *vm, uc_vm_insn_t insn)
2208 {
2209         uc_value_t *v = uc_vm_stack_pop(vm);
2210         uc_value_t *nv;
2211         uint64_t u;
2212         int64_t n;
2213 
2214         nv = ucv_to_number(v);
2215         n = int64(nv, &u);
2216 
2217         if (n < 0) {
2218                 uc_vm_stack_push(vm, ucv_int64_new(~n));
2219         }
2220         else {
2221                 if (!u) u = (uint64_t)n;
2222 
2223                 uc_vm_stack_push(vm, ucv_uint64_new(~u));
2224         }
2225 
2226         ucv_put(nv);
2227         ucv_put(v);
2228 }
2229 
2230 static void
2231 uc_vm_insn_rel(uc_vm_t *vm, uc_vm_insn_t insn)
2232 {
2233         uc_value_t *r2 = uc_vm_stack_pop(vm);
2234         uc_value_t *r1 = uc_vm_stack_pop(vm);
2235 
2236         bool res = ucv_compare(insn, r1, r2, NULL);
2237 
2238         ucv_put(r1);
2239         ucv_put(r2);
2240 
2241         uc_vm_stack_push(vm, ucv_boolean_new(res));
2242 }
2243 
2244 static void
2245 uc_vm_insn_in(uc_vm_t *vm, uc_vm_insn_t insn)
2246 {
2247         uc_value_t *r2 = uc_vm_stack_pop(vm);
2248         uc_value_t *r1 = uc_vm_stack_pop(vm);
2249         uc_value_t *item;
2250         size_t arrlen, arridx;
2251         bool found = false;
2252 
2253         switch (ucv_type(r2)) {
2254         case UC_ARRAY:
2255                 for (arridx = 0, arrlen = ucv_array_length(r2);
2256                      arridx < arrlen; arridx++) {
2257                         item = ucv_array_get(r2, arridx);
2258 
2259                         if (uc_vm_test_strict_equality(r1, item, true)) {
2260                                 found = true;
2261                                 break;
2262                         }
2263                 }
2264 
2265                 break;
2266 
2267         case UC_OBJECT:
2268                 if (ucv_type(r1) == UC_STRING)
2269                         ucv_object_get(r2, ucv_string_get(r1), &found);
2270 
2271                 break;
2272 
2273         default:
2274                 found = false;
2275         }
2276 
2277         ucv_put(r1);
2278         ucv_put(r2);
2279 
2280         uc_vm_stack_push(vm, ucv_boolean_new(found));
2281 }
2282 
2283 static void
2284 uc_vm_insn_equality(uc_vm_t *vm, uc_vm_insn_t insn)
2285 {
2286         uc_value_t *r2 = uc_vm_stack_pop(vm);
2287         uc_value_t *r1 = uc_vm_stack_pop(vm);
2288         bool equal = uc_vm_test_strict_equality(r1, r2, false);
2289 
2290         ucv_put(r1);
2291         ucv_put(r2);
2292 
2293         uc_vm_stack_push(vm, ucv_boolean_new((insn == I_EQS) ? equal : !equal));
2294 }
2295 
2296 static void
2297 uc_vm_insn_not(uc_vm_t *vm, uc_vm_insn_t insn)
2298 {
2299         uc_value_t *r1 = uc_vm_stack_pop(vm);
2300 
2301         uc_vm_stack_push(vm, ucv_boolean_new(!ucv_is_truish(r1)));
2302         ucv_put(r1);
2303 }
2304 
2305 static void
2306 uc_vm_insn_jmp(uc_vm_t *vm, uc_vm_insn_t insn)
2307 {
2308         uc_callframe_t *frame = uc_vm_current_frame(vm);
2309         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
2310         int32_t addr = vm->arg.s32;
2311 
2312         /* ip already has been incremented */
2313         addr -= 5;
2314 
2315         if (frame->ip + addr < chunk->entries ||
2316             frame->ip + addr >= chunk->entries + chunk->count) {
2317                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
2318                 return;
2319         }
2320 
2321         frame->ip += addr;
2322 }
2323 
2324 static void
2325 uc_vm_insn_jmpz(uc_vm_t *vm, uc_vm_insn_t insn)
2326 {
2327         uc_callframe_t *frame = uc_vm_current_frame(vm);
2328         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
2329         uc_value_t *v = uc_vm_stack_pop(vm);
2330         int32_t addr = vm->arg.s32;
2331 
2332         /* ip already has been incremented */
2333         addr -= 5;
2334 
2335         if (frame->ip + addr < chunk->entries ||
2336             frame->ip + addr >= chunk->entries + chunk->count) {
2337                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
2338                 return;
2339         }
2340 
2341         if (!ucv_is_truish(v))
2342                 frame->ip += addr;
2343 
2344         ucv_put(v);
2345 }
2346 
2347 static void
2348 uc_vm_insn_jmpnt(uc_vm_t *vm, uc_vm_insn_t insn)
2349 {
2350         uc_callframe_t *frame = uc_vm_current_frame(vm);
2351         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
2352         int16_t addr = (vm->arg.u32 & 0xffff) - 0x7fff;
2353         uint16_t types = (vm->arg.u32 >> 16) & 0x1fff;
2354         uint8_t depth = (vm->arg.u32 >> 29) & 0x7;
2355         uc_value_t *v = uc_vm_stack_peek(vm, 0);
2356         size_t i;
2357 
2358         /* ip already has been incremented */
2359         addr -= 5;
2360 
2361         if (frame->ip + addr < chunk->entries ||
2362             frame->ip + addr >= chunk->entries + chunk->count) {
2363                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
2364                 return;
2365         }
2366 
2367         if (!(types & (1u << ucv_type(v)))) {
2368                 for (i = 0; i <= depth; i++)
2369                         ucv_put(uc_vm_stack_pop(vm));
2370 
2371                 uc_vm_stack_push(vm, NULL);
2372                 frame->ip += addr;
2373         }
2374 }
2375 
2376 
2377 static void
2378 uc_vm_object_iterator_free(void *ud)
2379 {
2380         uc_object_iterator_t *iter = ud;
2381 
2382         uc_list_remove(&iter->list);
2383 }
2384 
2385 static uc_resource_type_t uc_vm_object_iterator_type = {
2386         .name = "object iterator",
2387         .free = uc_vm_object_iterator_free
2388 };
2389 
2390 static bool
2391 uc_vm_object_iterator_next(uc_vm_t *vm, uc_vm_insn_t insn,
2392                            uc_value_t *k, uc_value_t *v)
2393 {
2394         uc_resource_t *res = (uc_resource_t *)k;
2395         uc_object_t *obj = (uc_object_t *)v;
2396         uc_object_iterator_t *iter;
2397 
2398         if (!res) {
2399                 /* object is empty */
2400                 if (!obj->table->head)
2401                         return false;
2402 
2403                 res = xalloc(sizeof(*res) + sizeof(uc_object_iterator_t));
2404                 res->header.type = UC_RESOURCE;
2405                 res->header.refcount = 1;
2406                 res->type = &uc_vm_object_iterator_type;
2407 
2408                 iter = res->data = (char *)res + sizeof(*res);
2409                 iter->table = obj->table;
2410                 iter->u.pos = obj->table->head;
2411 
2412                 uc_list_insert(&uc_thread_context_get()->object_iterators, &iter->list);
2413         }
2414         else if (ucv_type(k) == UC_RESOURCE &&
2415                  res->type == &uc_vm_object_iterator_type && res->data != NULL) {
2416 
2417                 iter = res->data;
2418         }
2419         else {
2420                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid object iterator");
2421 
2422                 return false;
2423         }
2424 
2425         /* no next key */
2426         if (!iter->u.pos) {
2427                 uc_list_remove(&iter->list);
2428 
2429                 return false;
2430         }
2431 
2432         uc_vm_stack_push(vm, ucv_string_new(iter->u.pos->k));
2433 
2434         if (insn == I_NEXTKV)
2435                 uc_vm_stack_push(vm, ucv_get((uc_value_t *)iter->u.pos->v));
2436 
2437         uc_vm_stack_push(vm, &res->header);
2438         ucv_put(v);
2439 
2440         iter->u.pos = iter->u.pos->next;
2441 
2442         return true;
2443 }
2444 
2445 static bool
2446 uc_vm_array_iterator_next(uc_vm_t *vm, uc_vm_insn_t insn,
2447                           uc_value_t *k, uc_value_t *v)
2448 {
2449         uint64_t n;
2450 
2451         if (!k) {
2452                 /* array is empty */
2453                 if (!ucv_array_length(v))
2454                         return false;
2455 
2456                 k = ucv_resource_new(NULL, NULL);
2457                 n = 0;
2458         }
2459         else if (ucv_type(k) == UC_RESOURCE) {
2460                 n = (uintptr_t)ucv_resource_data(k, NULL);
2461         }
2462         else {
2463                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid array iterator");
2464 
2465                 return false;
2466         }
2467 
2468         /* no next index */
2469         if (n >= ucv_array_length(v))
2470                 return false;
2471 
2472         if (insn == I_NEXTKV)
2473                 uc_vm_stack_push(vm, ucv_uint64_new(n));
2474 
2475         uc_vm_stack_push(vm, ucv_get(ucv_array_get(v, n)));
2476 
2477         uc_vm_stack_push(vm, k);
2478         ucv_put(v);
2479 
2480         ((uc_resource_t *)k)->data = (void *)(uintptr_t)(n + 1);
2481 
2482         return true;
2483 }
2484 
2485 static void
2486 uc_vm_insn_next(uc_vm_t *vm, uc_vm_insn_t insn)
2487 {
2488         uc_value_t *k = uc_vm_stack_pop(vm);
2489         uc_value_t *v = uc_vm_stack_pop(vm);
2490 
2491         switch (ucv_type(v)) {
2492         case UC_OBJECT:
2493                 if (uc_vm_object_iterator_next(vm, insn, k, v))
2494                         return;
2495 
2496                 break;
2497 
2498         case UC_ARRAY:
2499                 if (uc_vm_array_iterator_next(vm, insn, k, v))
2500                         return;
2501 
2502                 break;
2503 
2504         default:
2505                 break;
2506         }
2507 
2508         uc_vm_stack_push(vm, NULL);
2509         uc_vm_stack_push(vm, NULL);
2510 
2511         if (insn == I_NEXTKV)
2512                 uc_vm_stack_push(vm, NULL);
2513 
2514         ucv_put(k);
2515         ucv_put(v);
2516 }
2517 
2518 static void
2519 uc_vm_insn_close_upval(uc_vm_t *vm, uc_vm_insn_t insn)
2520 {
2521         uc_vm_close_upvals(vm, vm->stack.count - 1);
2522         ucv_put(uc_vm_stack_pop(vm));
2523 }
2524 
2525 static void
2526 uc_vm_insn_call(uc_vm_t *vm, uc_vm_insn_t insn)
2527 {
2528         bool mcall = (vm->arg.u32 & 0x80000000);
2529         size_t nargs = (vm->arg.u32 & 0xffff);
2530         uc_value_t *fno = uc_vm_stack_peek(vm, nargs);
2531         uc_value_t *ctx = NULL;
2532 
2533         if (!ucv_is_arrowfn(fno))
2534                 ctx = mcall ? uc_vm_stack_peek(vm, nargs + 1) : NULL;
2535         else if (vm->callframes.count > 0)
2536                 ctx = uc_vm_current_frame(vm)->ctx;
2537 
2538         uc_vm_call_function(vm, ucv_get(ctx), ucv_get(fno), mcall, vm->arg.u32);
2539 }
2540 
2541 static void
2542 uc_vm_insn_print(uc_vm_t *vm, uc_vm_insn_t insn)
2543 {
2544         uc_value_t *v = uc_vm_stack_pop(vm);
2545         char *p;
2546 
2547         switch (ucv_type(v)) {
2548         case UC_OBJECT:
2549         case UC_ARRAY:
2550                 p = ucv_to_jsonstring(vm, v);
2551                 fwrite(p, 1, strlen(p), vm->output);
2552                 free(p);
2553                 break;
2554 
2555         case UC_STRING:
2556                 fwrite(ucv_string_get(v), 1, ucv_string_length(v), vm->output);
2557                 break;
2558 
2559         case UC_NULL:
2560                 break;
2561 
2562         default:
2563                 p = ucv_to_string(vm, v);
2564                 fwrite(p, 1, strlen(p), vm->output);
2565                 free(p);
2566         }
2567 
2568         ucv_put(v);
2569 }
2570 
2571 static void
2572 uc_vm_insn_delete(uc_vm_t *vm, uc_vm_insn_t insn)
2573 {
2574         uc_value_t *k = uc_vm_stack_pop(vm);
2575         uc_value_t *v = uc_vm_stack_pop(vm);
2576         bool rv;
2577 
2578         switch (ucv_type(v)) {
2579         case UC_OBJECT:
2580                 if (assert_mutable_value(vm, v)) {
2581                         rv = ucv_key_delete(vm, v, k);
2582                         uc_vm_stack_push(vm, ucv_boolean_new(rv));
2583                 }
2584 
2585                 break;
2586 
2587         default:
2588                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
2589                                       "left-hand side expression is %s",
2590                                       v ? "not an object" : "null");
2591 
2592                 break;
2593         }
2594 
2595         ucv_put(k);
2596         ucv_put(v);
2597 }
2598 
2599 static void
2600 uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
2601 {
2602         uc_callframe_t *frame = uc_vm_current_frame(vm);
2603         uc_program_t *prog = uc_vm_current_program(vm);
2604         uint16_t from = vm->arg.u32 & 0xffff;
2605         uint16_t to = vm->arg.u32 >> 16;
2606         uc_value_t *name, *modobj;
2607         uint32_t cidx;
2608 
2609         /* is a wildcard import * from ... */
2610         if (to == 0xffff) {
2611                 to = from;
2612                 modobj = ucv_object_new(vm);
2613 
2614                 /* instruction is followed by u16 containing the offset of the
2615                  * first module export and `from` times u32 values containing
2616                  * the constant indexes of the names */
2617                 for (from = frame->ip[0] * 0x100 + frame->ip[1], frame->ip += 2;
2618                      from < prog->exports.count && to > 0;
2619                      from++, to--) {
2620 
2621                         cidx = (
2622                                 frame->ip[0] * 0x1000000UL +
2623                                 frame->ip[1] * 0x10000UL +
2624                                 frame->ip[2] * 0x100UL +
2625                                 frame->ip[3]
2626                         );
2627 
2628                         frame->ip += 4;
2629 
2630                         name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
2631 
2632                         if (ucv_type(name) == UC_STRING && prog->exports.entries[from])
2633                                 ucv_object_add(modobj, ucv_string_get(name),
2634                                         ucv_get(&prog->exports.entries[from]->header));
2635 
2636                         ucv_put(name);
2637                 }
2638 
2639                 ucv_set_constant(modobj, true);
2640 
2641                 uc_vm_stack_push(vm, modobj);
2642         }
2643 
2644         /* module export available, patch into upvalue */
2645         else if (from < prog->exports.count && prog->exports.entries[from]) {
2646                 frame->closure->upvals[to] = prog->exports.entries[from];
2647                 ucv_get(&prog->exports.entries[from]->header);
2648         }
2649 
2650         /* module export missing, e.g. due to premature return in module,
2651          * patch up dummy upvalue ref with `null` value */
2652         else {
2653                 frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0);
2654                 frame->closure->upvals[to]->closed = true;
2655         }
2656 }
2657 
2658 static void
2659 uc_vm_insn_export(uc_vm_t *vm, uc_vm_insn_t insn)
2660 {
2661         uc_callframe_t *frame = uc_vm_current_frame(vm);
2662         uc_program_t *prog = uc_vm_current_program(vm);
2663         uc_upvalref_t *ref = uc_vm_capture_upval(vm, frame->stackframe + vm->arg.u32);
2664 
2665         uc_vector_push(&prog->exports, ref);
2666         ucv_get(&ref->header);
2667 }
2668 
2669 static void
2670 uc_vm_insn_dynload(uc_vm_t *vm, uc_vm_insn_t insn)
2671 {
2672         uc_callframe_t *frame = uc_vm_current_frame(vm);
2673         uc_value_t *name, *export, *modscope, *modobj;
2674         uint16_t count = vm->arg.u32 & 0xffff;
2675         uint16_t to = vm->arg.u32 >> 16;
2676         uint32_t cidx;
2677         bool found;
2678 
2679         /* Attempt to load module. Will raise exception on error */
2680         name = uc_vm_stack_pop(vm);
2681         modscope = uc_require_library(vm, name, true);
2682         ucv_put(name);
2683 
2684         if (!modscope)
2685                 return;
2686 
2687         /* If count is zero, we're doing a wildcard import. Shallow copy module
2688          * object, mark it constant and patch into the target upvalue. */
2689         if (count == 0) {
2690                 modobj = ucv_object_new(vm);
2691 
2692                 ucv_object_foreach(modscope, k, v)
2693                         ucv_object_add(modobj, k, ucv_get(v));
2694 
2695                 ucv_set_constant(modobj, true);
2696 
2697                 uc_vm_stack_push(vm, modobj);
2698         }
2699 
2700         /* ... otherwise we're importing a specific list of names */
2701         else {
2702                 /* Instruction is followed by `count` times u32 values containing
2703                  * the import name constant indexes */
2704                 while (count > 0) {
2705                         cidx = (
2706                                 frame->ip[0] * 0x1000000UL +
2707                                 frame->ip[1] * 0x10000UL +
2708                                 frame->ip[2] * 0x100UL +
2709                                 frame->ip[3]
2710                         );
2711 
2712                         frame->ip += 4;
2713 
2714                         name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
2715                         export = ucv_object_get(modscope, ucv_string_get(name), &found);
2716 
2717                         if (!found) {
2718                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
2719                                                       "Module does not export %s",
2720                                                       ucv_string_get(name));
2721 
2722                                 ucv_put(name);
2723                                 ucv_put(modscope);
2724 
2725                                 return;
2726                         }
2727 
2728                         ucv_put(name);
2729 
2730                         frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0);
2731                         frame->closure->upvals[to]->closed = true;
2732                         frame->closure->upvals[to]->value = ucv_get(export);
2733 
2734                         count--;
2735                         to++;
2736                 }
2737         }
2738 
2739         ucv_put(modscope);
2740 }
2741 
2742 static void
2743 uc_vm_gc_step(uc_vm_t *vm)
2744 {
2745         size_t curr_count = 0, prev_count = 0;
2746         uc_weakref_t *ref;
2747 
2748         if (!(vm->gc_flags & GC_ENABLED))
2749                 return;
2750 
2751         if (vm->alloc_refs >= vm->gc_interval) {
2752                 if (vm->trace) {
2753                         for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
2754                                 prev_count++;
2755 
2756                         ucv_gc(vm);
2757 
2758                         for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
2759                                 curr_count++;
2760 
2761                         fprintf(stderr, "! GC reclaimed %zu object(s)\n", prev_count - curr_count);
2762                 }
2763                 else {
2764                         ucv_gc(vm);
2765                 }
2766         }
2767 }
2768 
2769 static uc_value_t *
2770 uc_vm_callframe_pop(uc_vm_t *vm)
2771 {
2772         uc_callframe_t *frame = uc_vm_current_frame(vm);
2773         uc_value_t *retval;
2774 
2775         /* close upvalues */
2776         uc_vm_close_upvals(vm, frame->stackframe);
2777 
2778         if (vm->stack.count > frame->stackframe)
2779                 retval = uc_vm_stack_pop(vm);
2780         else
2781                 retval = NULL;
2782 
2783         /* reset function stack frame */
2784         while (vm->stack.count > frame->stackframe)
2785                 ucv_put(uc_vm_stack_pop(vm));
2786 
2787         /* for method calls, release context as well */
2788         if (frame->mcall)
2789                 ucv_put(uc_vm_stack_pop(vm));
2790 
2791         /* release function */
2792         if (frame->closure)
2793                 ucv_put(&frame->closure->header);
2794 
2795         if (frame->cfunction)
2796                 ucv_put(&frame->cfunction->header);
2797 
2798         /* release context */
2799         ucv_put(frame->ctx);
2800 
2801         vm->callframes.count--;
2802 
2803         return retval;
2804 }
2805 
2806 static void
2807 uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex)
2808 {
2809         uc_value_t *ctx;
2810 
2811         if (ex->type == EXCEPTION_USER)
2812                 fprintf(stderr, "%s\n", ex->message);
2813         else
2814                 fprintf(stderr, "%s: %s\n",
2815                             exception_type_strings[ex->type] ? exception_type_strings[ex->type] : "Error",
2816                             ex->message);
2817 
2818         ctx = ucv_object_get(ucv_array_get(ex->stacktrace, 0), "context", NULL);
2819 
2820         if (ctx)
2821                 fprintf(stderr, "%s\n", ucv_string_get(ctx));
2822 
2823         fprintf(stderr, "\n");
2824 }
2825 
2826 uc_exception_type_t
2827 uc_vm_signal_dispatch(uc_vm_t *vm)
2828 {
2829         uc_exception_type_t ex;
2830         uc_value_t *handler;
2831         uint64_t mask;
2832         size_t i, j;
2833         int sig, rv;
2834 
2835         if (!vm->config->setup_signal_handlers)
2836                 return EXCEPTION_NONE;
2837 
2838         for (i = 0; i < ARRAY_SIZE(vm->signal.raised); i++) {
2839                 if (!vm->signal.raised[i])
2840                         continue;
2841 
2842                 do {
2843                         rv = read(vm->signal.sigpipe[0], &sig, sizeof(sig));
2844                 } while (rv > 0 || (rv == -1 && errno == EINTR));
2845 
2846                 for (j = 0; j < 64; j++) {
2847                         mask = 1ull << j;
2848 
2849                         if (vm->signal.raised[i] & mask) {
2850                                 vm->signal.raised[i] &= ~mask;
2851 
2852                                 sig = i * 64 + j;
2853                                 handler = ucv_array_get(vm->signal.handler, sig);
2854 
2855                                 if (ucv_is_callable(handler)) {
2856                                         uc_vm_stack_push(vm, ucv_get(handler));
2857                                         uc_vm_stack_push(vm, ucv_int64_new(sig));
2858 
2859                                         ex = uc_vm_call(vm, false, 1);
2860 
2861                                         if (ex != EXCEPTION_NONE)
2862                                                 return ex;
2863 
2864                                         ucv_put(uc_vm_stack_pop(vm));
2865                                 }
2866                         }
2867                 }
2868         }
2869 
2870         return EXCEPTION_NONE;
2871 }
2872 
2873 static uc_vm_status_t
2874 uc_vm_execute_chunk(uc_vm_t *vm)
2875 {
2876         uc_callframe_t *frame = NULL;
2877         uc_chunk_t *chunk = NULL;
2878         size_t caller = vm->callframes.count - 1;
2879         uc_value_t *retval;
2880         uc_vm_insn_t insn;
2881         uint8_t *ip;
2882 
2883         while (vm->callframes.count > caller) {
2884                 frame = &vm->callframes.entries[vm->callframes.count - 1];
2885                 chunk = uc_vm_frame_chunk(frame);
2886 
2887                 if (!chunk)
2888                         break;
2889 
2890                 if (vm->trace) {
2891                         ip = frame->ip;
2892                         insn = uc_vm_decode_insn(vm, frame, chunk);
2893                         uc_dump_insn(vm, ip, insn);
2894                 }
2895                 else {
2896                         insn = uc_vm_decode_insn(vm, frame, chunk);
2897                 }
2898 
2899                 switch (insn) {
2900                 case I_LOAD:
2901                 case I_LOAD8:
2902                 case I_LOAD16:
2903                 case I_LOAD32:
2904                         uc_vm_insn_load(vm, insn);
2905                         break;
2906 
2907                 case I_LREXP:
2908                         uc_vm_insn_load_regexp(vm, insn);
2909                         break;
2910 
2911                 case I_LNULL:
2912                         uc_vm_insn_load_null(vm, insn);
2913                         break;
2914 
2915                 case I_LTRUE:
2916                 case I_LFALSE:
2917                         uc_vm_insn_load_bool(vm, insn);
2918                         break;
2919 
2920                 case I_LTHIS:
2921                         uc_vm_stack_push(vm, ucv_get(frame->ctx));
2922                         break;
2923 
2924                 case I_LVAR:
2925                         uc_vm_insn_load_var(vm, insn);
2926                         break;
2927 
2928                 case I_LVAL:
2929                         uc_vm_insn_load_val(vm, insn);
2930                         break;
2931 
2932                 case I_PVAL:
2933                         uc_vm_insn_peek_val(vm, insn);
2934                         break;
2935 
2936                 case I_LUPV:
2937                         uc_vm_insn_load_upval(vm, insn);
2938                         break;
2939 
2940                 case I_LLOC:
2941                         uc_vm_insn_load_local(vm, insn);
2942                         break;
2943 
2944                 case I_CLFN:
2945                 case I_ARFN:
2946                         uc_vm_insn_load_closure(vm, insn);
2947                         break;
2948 
2949                 case I_NARR:
2950                         uc_vm_insn_narr(vm, insn);
2951                         break;
2952 
2953                 case I_PARR:
2954                         uc_vm_insn_parr(vm, insn);
2955                         break;
2956 
2957                 case I_MARR:
2958                         uc_vm_insn_marr(vm, insn);
2959                         break;
2960 
2961                 case I_NOBJ:
2962                         uc_vm_insn_nobj(vm, insn);
2963                         break;
2964 
2965                 case I_SOBJ:
2966                         uc_vm_insn_sobj(vm, insn);
2967                         break;
2968 
2969                 case I_MOBJ:
2970                         uc_vm_insn_mobj(vm, insn);
2971                         break;
2972 
2973                 case I_SVAR:
2974                         uc_vm_insn_store_var(vm, insn);
2975                         break;
2976 
2977                 case I_SVAL:
2978                         uc_vm_insn_store_val(vm, insn);
2979                         break;
2980 
2981                 case I_SUPV:
2982                         uc_vm_insn_store_upval(vm, insn);
2983                         break;
2984 
2985                 case I_SLOC:
2986                         uc_vm_insn_store_local(vm, insn);
2987                         break;
2988 
2989                 case I_UVAR:
2990                         uc_vm_insn_update_var(vm, insn);
2991                         break;
2992 
2993                 case I_UVAL:
2994                         uc_vm_insn_update_val(vm, insn);
2995                         break;
2996 
2997                 case I_UUPV:
2998                         uc_vm_insn_update_upval(vm, insn);
2999                         break;
3000 
3001                 case I_ULOC:
3002                         uc_vm_insn_update_local(vm, insn);
3003                         break;
3004 
3005                 case I_ADD:
3006                 case I_SUB:
3007                 case I_MUL:
3008                 case I_DIV:
3009                 case I_MOD:
3010                 case I_EXP:
3011                         uc_vm_insn_arith(vm, insn);
3012                         break;
3013 
3014                 case I_PLUS:
3015                 case I_MINUS:
3016                         uc_vm_insn_plus_minus(vm, insn);
3017                         break;
3018 
3019                 case I_LSHIFT:
3020                 case I_RSHIFT:
3021                 case I_BAND:
3022                 case I_BXOR:
3023                 case I_BOR:
3024                         uc_vm_insn_bitop(vm, insn);
3025                         break;
3026 
3027                 case I_COMPL:
3028                         uc_vm_insn_complement(vm, insn);
3029                         break;
3030 
3031                 case I_EQS:
3032                 case I_NES:
3033                         uc_vm_insn_equality(vm, insn);
3034                         break;
3035 
3036                 case I_EQ:
3037                 case I_NE:
3038                 case I_LT:
3039                 case I_LE:
3040                 case I_GT:
3041                 case I_GE:
3042                         uc_vm_insn_rel(vm, insn);
3043                         break;
3044 
3045                 case I_IN:
3046                         uc_vm_insn_in(vm, insn);
3047                         break;
3048 
3049                 case I_NOT:
3050                         uc_vm_insn_not(vm, insn);
3051                         break;
3052 
3053                 case I_JMP:
3054                         uc_vm_insn_jmp(vm, insn);
3055                         break;
3056 
3057                 case I_JMPZ:
3058                         uc_vm_insn_jmpz(vm, insn);
3059                         break;
3060 
3061                 case I_JMPNT:
3062                         uc_vm_insn_jmpnt(vm, insn);
3063                         break;
3064 
3065                 case I_NEXTK:
3066                 case I_NEXTKV:
3067                         uc_vm_insn_next(vm, insn);
3068                         break;
3069 
3070                 case I_COPY:
3071                         uc_vm_stack_push(vm, ucv_get(uc_vm_stack_peek(vm, vm->arg.u8)));
3072                         break;
3073 
3074                 case I_POP:
3075                         ucv_put(uc_vm_stack_pop(vm));
3076                         uc_vm_gc_step(vm);
3077                         break;
3078 
3079                 case I_CUPV:
3080                         uc_vm_insn_close_upval(vm, insn);
3081                         break;
3082 
3083                 case I_CALL:
3084                         uc_vm_insn_call(vm, insn);
3085                         break;
3086 
3087                 case I_RETURN:
3088                         retval = uc_vm_callframe_pop(vm);
3089 
3090                         uc_vm_stack_push(vm, retval);
3091 
3092                         if (vm->callframes.count == 0)
3093                                 return STATUS_OK;
3094                         break;
3095 
3096                 case I_PRINT:
3097                         uc_vm_insn_print(vm, insn);
3098                         break;
3099 
3100                 case I_DELETE:
3101                         uc_vm_insn_delete(vm, insn);
3102                         break;
3103 
3104                 case I_IMPORT:
3105                         uc_vm_insn_import(vm, insn);
3106                         break;
3107 
3108                 case I_EXPORT:
3109                         uc_vm_insn_export(vm, insn);
3110                         break;
3111 
3112                 case I_DYNLOAD:
3113                         uc_vm_insn_dynload(vm, insn);
3114                         break;
3115 
3116                 default:
3117                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "unknown opcode %d", insn);
3118                         break;
3119                 }
3120 
3121 exception:
3122                 /* previous instruction raised exception */
3123                 if (vm->exception.type != EXCEPTION_NONE) {
3124                         /* VM termination was requested */
3125                         if (vm->exception.type == EXCEPTION_EXIT) {
3126                                 uc_vm_reset_callframes(vm);
3127 
3128                                 return STATUS_EXIT;
3129                         }
3130 
3131                         /* walk up callframes until something handles the exception or the original caller is reached */
3132                         while (!uc_vm_handle_exception(vm)) {
3133                                 /* no further callframe, report unhandled exception and terminate */
3134                                 if (vm->callframes.count == 0)
3135                                         return ERROR_RUNTIME;
3136 
3137                                 /* if VM returned into native function, don't bubble up */
3138                                 if (!vm->callframes.entries[vm->callframes.count - 1].closure)
3139                                         return ERROR_RUNTIME;
3140 
3141                                 /* no exception handler in current function, pop callframe */
3142                                 ucv_put(uc_vm_callframe_pop(vm));
3143 
3144                                 /* do not bubble past original call depth */
3145                                 if (vm->callframes.count <= caller)
3146                                         return ERROR_RUNTIME;
3147                         }
3148                 }
3149 
3150                 /* run handler for signal(s) delivered during previous instruction */
3151                 if (uc_vm_signal_dispatch(vm) != EXCEPTION_NONE)
3152                         goto exception;
3153         }
3154 
3155         return STATUS_OK;
3156 }
3157 
3158 uc_vm_status_t
3159 uc_vm_execute(uc_vm_t *vm, uc_program_t *program, uc_value_t **retval)
3160 {
3161         uc_function_t *fn = uc_program_entry(program);
3162         uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false);
3163         uc_vm_status_t status;
3164         uc_callframe_t *frame;
3165         uc_stringbuf_t *buf;
3166         uc_value_t *val;
3167 
3168         frame = uc_vector_push(&vm->callframes, {
3169                 .closure = closure,
3170                 .stackframe = 0,
3171                 .ip = closure->function->chunk.entries,
3172                 .strict = fn->strict
3173         });
3174 
3175         if (vm->trace) {
3176                 buf = xprintbuf_new();
3177 
3178                 uc_source_context_format(buf, uc_vm_frame_source(frame), 0, true);
3179 
3180                 fwrite(buf->buf, 1, printbuf_length(buf), stderr);
3181                 printbuf_free(buf);
3182 
3183                 uc_vm_frame_dump(vm, frame);
3184         }
3185 
3186         //uc_vm_stack_push(vm, closure->header.jso);
3187         uc_vm_stack_push(vm, NULL);
3188 
3189         status = uc_vm_execute_chunk(vm);
3190 
3191         switch (status) {
3192         case STATUS_OK:
3193                 val = uc_vm_stack_pop(vm);
3194 
3195                 if (retval)
3196                         *retval = val;
3197                 else
3198                         ucv_put(val);
3199 
3200                 break;
3201 
3202         case STATUS_EXIT:
3203                 if (retval)
3204                         *retval = ucv_int64_new(vm->arg.s32);
3205 
3206                 break;
3207 
3208         default:
3209                 if (vm->exhandler)
3210                         vm->exhandler(vm, &vm->exception);
3211 
3212                 if (retval)
3213                         *retval = NULL;
3214 
3215                 break;
3216         }
3217 
3218         return status;
3219 }
3220 
3221 uc_exception_type_t
3222 uc_vm_call(uc_vm_t *vm, bool mcall, size_t nargs)
3223 {
3224         uc_value_t *ctx = mcall ? ucv_get(uc_vm_stack_peek(vm, nargs + 1)) : NULL;
3225         uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, nargs));
3226 
3227         uc_vm_clear_exception(vm);
3228 
3229         if (uc_vm_call_function(vm, ctx, fno, mcall, nargs & 0xffff)) {
3230                 if (ucv_type(fno) != UC_CFUNCTION)
3231                         uc_vm_execute_chunk(vm);
3232         }
3233 
3234         return vm->exception.type;
3235 }
3236 
3237 uc_value_t *
3238 uc_vm_scope_get(uc_vm_t *vm)
3239 {
3240         return vm->globals;
3241 }
3242 
3243 void
3244 uc_vm_scope_set(uc_vm_t *vm, uc_value_t *ctx)
3245 {
3246         ucv_put(vm->globals);
3247         vm->globals = ctx;
3248 }
3249 
3250 uc_value_t *
3251 uc_vm_invoke(uc_vm_t *vm, const char *fname, size_t nargs, ...)
3252 {
3253         uc_exception_type_t ex;
3254         uc_value_t *fno, *arg;
3255         va_list ap;
3256         size_t i;
3257 
3258         fno = ucv_property_get(vm->globals, fname);
3259 
3260         if (!ucv_is_callable(fno))
3261                 return NULL;
3262 
3263         uc_vm_stack_push(vm, ucv_get(fno));
3264 
3265         va_start(ap, nargs);
3266 
3267         for (i = 0; i < nargs; i++) {
3268                 arg = va_arg(ap, uc_value_t *);
3269                 uc_vm_stack_push(vm, ucv_get(arg));
3270         }
3271 
3272         va_end(ap);
3273 
3274         ex = uc_vm_call(vm, false, nargs);
3275 
3276         if (ex) {
3277                 if (vm->exhandler)
3278                         vm->exhandler(vm, &vm->exception);
3279 
3280                 return NULL;
3281         }
3282 
3283         return uc_vm_stack_pop(vm);
3284 }
3285 
3286 uc_exception_handler_t *
3287 uc_vm_exception_handler_get(uc_vm_t *vm)
3288 {
3289         return vm->exhandler;
3290 }
3291 
3292 void
3293 uc_vm_exception_handler_set(uc_vm_t *vm, uc_exception_handler_t *exhandler)
3294 {
3295         vm->exhandler = exhandler;
3296 }
3297 
3298 uint32_t
3299 uc_vm_trace_get(uc_vm_t *vm)
3300 {
3301         return vm->trace;
3302 }
3303 
3304 void
3305 uc_vm_trace_set(uc_vm_t *vm, uint32_t level)
3306 {
3307         vm->trace = level;
3308 }
3309 
3310 bool
3311 uc_vm_registry_exists(uc_vm_t *vm, const char *key)
3312 {
3313         bool exists;
3314 
3315         ucv_object_get(vm->registry, key, &exists);
3316 
3317         return exists;
3318 }
3319 
3320 uc_value_t *
3321 uc_vm_registry_get(uc_vm_t *vm, const char *key)
3322 {
3323         return ucv_object_get(vm->registry, key, NULL);
3324 }
3325 
3326 void
3327 uc_vm_registry_set(uc_vm_t *vm, const char *key, uc_value_t *value)
3328 {
3329         if (!vm->registry)
3330                 vm->registry = ucv_object_new(vm);
3331 
3332         ucv_object_add(vm->registry, key, value);
3333 }
3334 
3335 bool
3336 uc_vm_registry_delete(uc_vm_t *vm, const char *key)
3337 {
3338         return ucv_object_delete(vm->registry, key);
3339 }
3340 
3341 bool
3342 uc_vm_gc_start(uc_vm_t *vm, uint16_t interval)
3343 {
3344         bool changed = false;
3345 
3346         if (vm->gc_interval != interval) {
3347                 vm->gc_interval = interval;
3348                 changed = true;
3349         }
3350 
3351         if (!(vm->gc_flags & GC_ENABLED)) {
3352                 vm->gc_flags |= GC_ENABLED;
3353                 changed = true;
3354         }
3355 
3356         return changed;
3357 }
3358 
3359 bool
3360 uc_vm_gc_stop(uc_vm_t *vm)
3361 {
3362         if (!(vm->gc_flags & GC_ENABLED))
3363                 return false;
3364 
3365         vm->gc_flags &= ~GC_ENABLED;
3366 
3367         return true;
3368 }
3369 
3370 void
3371 uc_vm_signal_raise(uc_vm_t *vm, int signo)
3372 {
3373         uint8_t signum = signo;
3374 
3375         if (signo <= 0 || signo >= UC_SYSTEM_SIGNAL_COUNT)
3376                 return;
3377 
3378         vm->signal.raised[signo / 64] |= (1ull << (signo % 64));
3379 
3380         if (write(vm->signal.sigpipe[1], &signum, sizeof(signum)) == -1) {}
3381 }
3382 
3383 int
3384 uc_vm_signal_notifyfd(uc_vm_t *vm)
3385 {
3386         return vm->signal.sigpipe[0];
3387 }
3388 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt