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

Sources/ucode/vm.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt