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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt