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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt