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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt