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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt