• 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(ctx);
532                                 ucv_put(fno);
533                                 ucv_put(ellip);
534 
535                                 return false;
536                         }
537 
538                         /* ... and push each spread array value as argument to the stack */
539                         for (j = 0; j < ucv_array_length(arg); j++)
540                                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(arg, j)));
541 
542                         ucv_put(arg);
543                 }
544 
545                 /* push remaining non-spread arguments to the stack */
546                 for (i = slot; i > 0; i--)
547                         uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, i - 1)));
548 
549                 /* free temp array */
550                 ucv_put(ellip);
551 
552                 /* update arg count */
553                 nargs = vm->stack.count - stackoff - 1;
554         }
555 
556         /* is a native function */
557         if (ucv_type(fno) == UC_CFUNCTION) {
558                 uc_vm_call_native(vm, ctx, (uc_cfunction_t *)fno, mcall, nargs);
559 
560                 return true;
561         }
562 
563         if (ucv_type(fno) != UC_CLOSURE) {
564                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "left-hand side is not a function");
565                 ucv_put(ctx);
566                 ucv_put(fno);
567 
568                 return false;
569         }
570 
571         closure = (uc_closure_t *)fno;
572         function = closure->function;
573 
574         /* fewer arguments on stack than function expects => pad */
575         if (nargs < function->nargs) {
576                 for (i = nargs; i < function->nargs; i++) {
577                         if (function->vararg && (i + 1) == function->nargs)
578                                 uc_vm_stack_push(vm, ucv_array_new_length(vm, 0));
579                         else
580                                 uc_vm_stack_push(vm, NULL);
581                 }
582         }
583 
584         /* more arguments on stack than function expects... */
585         else if (nargs > function->nargs - function->vararg) {
586                 /* is a vararg function => pass excess args as array */
587                 if (function->vararg) {
588                         ellip = ucv_array_new_length(vm, nargs - (function->nargs - 1));
589 
590                         for (i = function->nargs; i <= nargs; i++)
591                                 ucv_array_push(ellip, uc_vm_stack_peek(vm, nargs - i));
592 
593                         for (i = function->nargs; i <= nargs; i++)
594                                 uc_vm_stack_pop(vm);
595 
596                         uc_vm_stack_push(vm, ellip);
597                 }
598 
599                 /* static amount of args => drop excess values */
600                 else {
601                         for (i = function->nargs; i < nargs; i++)
602                                 ucv_put(uc_vm_stack_pop(vm));
603                 }
604         }
605 
606         uc_vector_grow(&vm->callframes);
607 
608         frame = &vm->callframes.entries[vm->callframes.count++];
609         frame->stackframe = stackoff;
610         frame->cfunction = NULL;
611         frame->closure = closure;
612         frame->ctx = ctx;
613         frame->ip = function->chunk.entries;
614         frame->mcall = mcall;
615         frame->strict = function->strict;
616 
617         if (vm->trace)
618                 uc_vm_frame_dump(vm, frame);
619 
620         return true;
621 }
622 
623 static uc_source_t *last_source = NULL;
624 static size_t last_srcpos = 0;
625 
626 static void
627 uc_dump_insn(uc_vm_t *vm, uint8_t *pos, uc_vm_insn_t insn)
628 {
629         uc_callframe_t *frame = uc_vm_current_frame(vm);
630         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
631         uc_stringbuf_t *buf = NULL;
632         uc_value_t *cnst = NULL;
633         uc_source_t *source;
634         size_t srcpos;
635 
636         srcpos = uc_program_function_srcpos(frame->closure->function, pos - chunk->entries);
637         source = uc_vm_frame_source(frame);
638 
639         if (last_srcpos == 0 || last_source != source || srcpos != last_srcpos) {
640                 buf = xprintbuf_new();
641 
642                 uc_source_context_format(buf, source, srcpos, true);
643                 fwrite(buf->buf, 1, printbuf_length(buf), stderr);
644                 printbuf_free(buf);
645 
646                 last_source = source;
647                 last_srcpos = srcpos;
648         }
649 
650         fprintf(stderr, "%08zx  %s", pos - chunk->entries, insn_names[insn]);
651 
652         switch (insn_operand_bytes[insn]) {
653         case 0:
654                 break;
655 
656         case -1:
657                 fprintf(stderr, " {%s%hhd}", vm->arg.s8 < 0 ? "" : "+", vm->arg.s8);
658                 break;
659 
660         case -2:
661                 fprintf(stderr, " {%c0x%hx}",
662                         vm->arg.s16 < 0 ? '-' : '+',
663                         (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16));
664                 break;
665 
666         case -4:
667                 fprintf(stderr, " {%c0x%x}",
668                         vm->arg.s32 < 0 ? '-' : '+',
669                         (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32));
670                 break;
671 
672         case 1:
673                 fprintf(stderr, " {%hhu}", vm->arg.u8);
674                 break;
675 
676         case 2:
677                 fprintf(stderr, " {0x%hx}", vm->arg.u16);
678                 break;
679 
680         case 4:
681                 fprintf(stderr, " {0x%x}", vm->arg.u32);
682                 break;
683 
684         default:
685                 fprintf(stderr, " (unknown operand format: %" PRId8 ")", insn_operand_bytes[insn]);
686                 break;
687         }
688 
689         switch (insn) {
690         case I_LOAD:
691         case I_LVAR:
692         case I_SVAR:
693                 cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32);
694 
695                 fprintf(stderr, "\t; %s",
696                         cnst ? uc_vm_format_val(vm, cnst) : "(?)");
697 
698                 ucv_put(cnst);
699                 break;
700 
701         case I_LLOC:
702         case I_LUPV:
703         case I_SLOC:
704         case I_SUPV:
705                 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32, (insn == I_LUPV || insn == I_SUPV));
706 
707                 fprintf(stderr, "\t; %s",
708                         cnst ? uc_vm_format_val(vm, cnst) : "(?)");
709 
710                 ucv_put(cnst);
711                 break;
712 
713         case I_ULOC:
714         case I_UUPV:
715                 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32 & 0x00ffffff, (insn == I_UUPV));
716                 /* fall through */
717 
718         case I_UVAR:
719                 if (!cnst)
720                         cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32 & 0x00ffffff);
721 
722                 fprintf(stderr, "\t; %s (%s)",
723                         cnst ? uc_vm_format_val(vm, cnst) : "(?)",
724                         insn_names[vm->arg.u32 >> 24]);
725 
726                 ucv_put(cnst);
727                 break;
728 
729         case I_UVAL:
730                 fprintf(stderr, "\t; (%s)", insn_names[vm->arg.u32]);
731                 break;
732 
733         default:
734                 break;
735         }
736 
737         fprintf(stderr, "\n");
738 }
739 
740 static uc_value_t *
741 uc_vm_exception_tostring(uc_vm_t *vm, size_t nargs)
742 {
743         uc_callframe_t *frame = uc_vm_current_frame(vm);
744         uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL);
745 
746         return message ? ucv_get(message) : ucv_string_new("Exception");
747 }
748 
749 static uc_value_t *exception_prototype = NULL;
750 
751 static uc_value_t *
752 uc_vm_exception_new(uc_vm_t *vm, uc_exception_type_t type, const char *message, uc_value_t *stacktrace)
753 {
754         uc_value_t *exo;
755 
756         if (exception_prototype == NULL) {
757                 exception_prototype = ucv_object_new(vm);
758 
759                 ucv_object_add(exception_prototype, "tostring",
760                         ucv_cfunction_new("tostring", uc_vm_exception_tostring));
761         }
762 
763         exo = ucv_object_new(vm);
764 
765         ucv_object_add(exo, "type", ucv_string_new(exception_type_strings[type]));
766         ucv_object_add(exo, "message", ucv_string_new(message));
767         ucv_object_add(exo, "stacktrace", ucv_get(stacktrace));
768 
769         ucv_prototype_set(exo, ucv_get(exception_prototype));
770 
771         return exo;
772 }
773 
774 static void
775 uc_vm_clear_exception(uc_vm_t *vm)
776 {
777         vm->exception.type = EXCEPTION_NONE;
778 
779         ucv_put(vm->exception.stacktrace);
780         vm->exception.stacktrace = NULL;
781 
782         free(vm->exception.message);
783         vm->exception.message = NULL;
784 }
785 
786 static bool
787 uc_vm_handle_exception(uc_vm_t *vm)
788 {
789         uc_callframe_t *frame = NULL;
790         uc_chunk_t *chunk = NULL;
791         uc_value_t *exo;
792         size_t i, pos;
793 
794         if (vm->callframes.count)
795                 frame = uc_vm_current_frame(vm);
796 
797         if (!frame || !frame->closure)
798                 return false;
799 
800         chunk = uc_vm_frame_chunk(frame);
801         pos = frame->ip - chunk->entries;
802 
803         /* iterate the known exception ranges, see if the current ip falls into any of them */
804         for (i = 0; i < chunk->ehranges.count; i++) {
805                 /* skip nonmatching ranges */
806                 if (pos < chunk->ehranges.entries[i].from ||
807                     pos >= chunk->ehranges.entries[i].to)
808                         continue;
809 
810                 /* we found a matching range... first unwind stack */
811                 while (vm->stack.count > frame->stackframe + chunk->ehranges.entries[i].slot)
812                         ucv_put(uc_vm_stack_pop(vm));
813 
814                 /* prepare exception object and expose it to user handler code */
815                 exo = uc_vm_exception_new(vm, vm->exception.type, vm->exception.message, vm->exception.stacktrace);
816 
817                 uc_vm_stack_push(vm, exo);
818 
819                 /* reset exception information */
820                 uc_vm_clear_exception(vm);
821 
822                 /* jump to exception handler */
823                 if (chunk->ehranges.entries[i].target >= chunk->count) {
824                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
825                         return false;
826                 }
827 
828 #if 0
829                 if (vm->trace && chunk->entries + chunk->ehranges.entries[i].target > frame->ip) {
830                         while (frame->ip < chunk->entries + chunk->ehranges.entries[i].target) {
831                                 fprintf(stderr, "(eh:skip) [%p:%zu] ", chunk, frame->ip - chunk->entries);
832                                 uc_dump_insn(vm, frame->ip, uc_vm_decode_insn(vm, frame, chunk));
833                         }
834                 }
835 #endif
836 
837                 frame->ip = chunk->entries + chunk->ehranges.entries[i].target;
838 
839                 return true;
840         }
841 
842         return false;
843 }
844 
845 static uc_value_t *
846 uc_vm_capture_stacktrace(uc_vm_t *vm, size_t i)
847 {
848         uc_value_t *stacktrace, *entry, *last = NULL;
849         uc_function_t *function;
850         uc_callframe_t *frame;
851         uc_source_t *source;
852         size_t off, srcpos;
853         char *name;
854 
855         stacktrace = ucv_array_new(vm);
856 
857         for (; i > 0; i--) {
858                 frame = &vm->callframes.entries[i - 1];
859                 entry = ucv_object_new(vm);
860 
861                 if (frame->closure) {
862                         function = frame->closure->function;
863                         source = uc_program_function_source(function);
864 
865                         off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1;
866                         srcpos = uc_program_function_srcpos(function, off);
867 
868                         ucv_object_add(entry, "filename", ucv_string_new(source->filename));
869                         ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(source, &srcpos)));
870                         ucv_object_add(entry, "byte", ucv_int64_new(srcpos));
871                 }
872 
873                 if (i > 1) {
874                         if (frame->closure) {
875                                 if (frame->closure->function->name[0])
876                                         name = frame->closure->function->name;
877                                 else if (frame->closure->is_arrow)
878                                         name = "[arrow function]";
879                                 else
880                                         name = "[anonymous function]";
881                         }
882                         else {
883                                 name = frame->cfunction->name;
884                         }
885 
886                         ucv_object_add(entry, "function", ucv_string_new(name));
887                 }
888 
889                 if (!ucv_is_equal(last, entry)) {
890                         ucv_array_push(stacktrace, entry);
891                         last = entry;
892                 }
893                 else {
894                         ucv_put(entry);
895                 }
896         }
897 
898         return stacktrace;
899 }
900 
901 static uc_value_t *
902 uc_vm_get_error_context(uc_vm_t *vm)
903 {
904         size_t offset, i, byte, line;
905         uc_value_t *stacktrace;
906         uc_callframe_t *frame;
907         uc_stringbuf_t *buf;
908         uc_chunk_t *chunk;
909 
910         /* skip to first non-native function call frame */
911         for (i = vm->callframes.count; i > 1; i--)
912                 if (vm->callframes.entries[i - 1].closure)
913                         break;
914 
915         frame = &vm->callframes.entries[i - 1];
916 
917         if (!frame->closure)
918                 return NULL;
919 
920         chunk = uc_vm_frame_chunk(frame);
921         offset = uc_program_function_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1);
922         stacktrace = uc_vm_capture_stacktrace(vm, i);
923 
924         buf = ucv_stringbuf_new();
925 
926         byte = offset;
927         line = uc_source_get_line(uc_program_function_source(frame->closure->function), &byte);
928 
929         if (line)
930                 uc_error_context_format(buf, uc_vm_frame_source(frame), stacktrace, offset);
931         else if (frame->ip != chunk->entries)
932                 ucv_stringbuf_printf(buf, "At instruction %zu", (frame->ip - chunk->entries) - 1);
933         else
934                 ucv_stringbuf_append(buf, "At start of program");
935 
936         ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf));
937 
938         return stacktrace;
939 }
940 
941 void __attribute__((format(printf, 3, 0)))
942 uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...)
943 {
944         va_list ap;
945 
946         vm->exception.type = type;
947 
948         free(vm->exception.message);
949 
950         va_start(ap, fmt);
951         xvasprintf(&vm->exception.message, fmt, ap);
952         va_end(ap);
953 
954         ucv_put(vm->exception.stacktrace);
955         vm->exception.stacktrace = uc_vm_get_error_context(vm);
956 }
957 
958 
959 static void
960 uc_vm_insn_load(uc_vm_t *vm, uc_vm_insn_t insn)
961 {
962         switch (insn) {
963         case I_LOAD:
964                 uc_vm_stack_push(vm, uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32));
965                 break;
966 
967         case I_LOAD8:
968                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u8));
969                 break;
970 
971         case I_LOAD16:
972                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u16));
973                 break;
974 
975         case I_LOAD32:
976                 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u32));
977                 break;
978 
979         default:
980                 break;
981         }
982 }
983 
984 static void
985 uc_vm_insn_load_regexp(uc_vm_t *vm, uc_vm_insn_t insn)
986 {
987         uc_value_t *re, *jstr = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
988         bool icase = false, newline = false, global = false;
989         char *str, *err = NULL;
990 
991         if (ucv_type(jstr) != UC_STRING || ucv_string_length(jstr) < 2) {
992                 uc_vm_stack_push(vm, NULL);
993                 ucv_put(jstr);
994 
995                 return;
996         }
997 
998         str = ucv_string_get(jstr);
999 
1000         global  = (*str & (1 << 0));
1001         icase   = (*str & (1 << 1));
1002         newline = (*str & (1 << 2));
1003 
1004         re = ucv_regexp_new(++str, icase, newline, global, &err);
1005 
1006         ucv_put(jstr);
1007 
1008         if (re)
1009                 uc_vm_stack_push(vm, re);
1010         else
1011                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err);
1012 
1013         free(err);
1014 }
1015 
1016 static void
1017 uc_vm_insn_load_null(uc_vm_t *vm, uc_vm_insn_t insn)
1018 {
1019         uc_vm_stack_push(vm, NULL);
1020 }
1021 
1022 static void
1023 uc_vm_insn_load_bool(uc_vm_t *vm, uc_vm_insn_t insn)
1024 {
1025         uc_vm_stack_push(vm, ucv_boolean_new(insn == I_LTRUE));
1026 }
1027 
1028 static void
1029 uc_vm_insn_load_var(uc_vm_t *vm, uc_vm_insn_t insn)
1030 {
1031         uc_value_t *name, *val = NULL;
1032         uc_value_t *scope, *next;
1033         bool found;
1034 
1035         scope = vm->globals;
1036         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
1037 
1038         while (ucv_type(name) == UC_STRING) {
1039                 val = ucv_object_get(scope, ucv_string_get(name), &found);
1040 
1041                 if (found)
1042                         break;
1043 
1044                 next = ucv_prototype_get(scope);
1045 
1046                 if (!next) {
1047                         if (uc_vm_is_strict(vm)) {
1048                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1049                                                       "access to undeclared variable %s",
1050                                                       ucv_string_get(name));
1051                         }
1052 
1053                         break;
1054                 }
1055 
1056                 scope = next;
1057         }
1058 
1059         ucv_put(name);
1060 
1061         uc_vm_stack_push(vm, ucv_get(val));
1062 }
1063 
1064 static void
1065 uc_vm_insn_load_val(uc_vm_t *vm, uc_vm_insn_t insn)
1066 {
1067         uc_value_t *k = uc_vm_stack_pop(vm);
1068         uc_value_t *v = uc_vm_stack_pop(vm);
1069 
1070         switch (ucv_type(v)) {
1071         case UC_RESOURCE:
1072         case UC_OBJECT:
1073         case UC_ARRAY:
1074                 uc_vm_stack_push(vm, ucv_key_get(vm, v, k));
1075                 break;
1076 
1077         default:
1078                 if (insn == I_QLVAL)
1079                         uc_vm_stack_push(vm, NULL);
1080                 else
1081                         uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1082                                               "left-hand side expression is %s",
1083                                               v ? "not an array or object" : "null");
1084 
1085                 break;
1086         }
1087 
1088         ucv_put(k);
1089         ucv_put(v);
1090 }
1091 
1092 static void
1093 uc_vm_insn_load_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1094 {
1095         uc_callframe_t *frame = uc_vm_current_frame(vm);
1096         uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32];
1097 
1098         if (ref->closed)
1099                 uc_vm_stack_push(vm, ucv_get(ref->value));
1100         else
1101                 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[ref->slot]));
1102 }
1103 
1104 static void
1105 uc_vm_insn_load_local(uc_vm_t *vm, uc_vm_insn_t insn)
1106 {
1107         uc_callframe_t *frame = uc_vm_current_frame(vm);
1108 
1109         uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32]));
1110 }
1111 
1112 static uc_upvalref_t *
1113 uc_vm_capture_upval(uc_vm_t *vm, size_t slot)
1114 {
1115         uc_upvalref_t *curr = vm->open_upvals;
1116         uc_upvalref_t *prev = NULL;
1117         uc_upvalref_t *created;
1118         char *s;
1119 
1120         while (curr && curr->slot > slot) {
1121                 prev = curr;
1122                 curr = curr->next;
1123         }
1124 
1125         if (curr && curr->slot == slot) {
1126                 if (vm->trace) {
1127                         s = ucv_to_string(NULL, vm->stack.entries[slot]);
1128                         fprintf(stderr, "  {+%zu} <%p> %s\n", slot, (void *)curr, s);
1129                         free(s);
1130                 }
1131 
1132                 return curr;
1133         }
1134 
1135         created = (uc_upvalref_t *)ucv_upvalref_new(slot);
1136         created->next = curr;
1137 
1138         if (vm->trace) {
1139                 s = ucv_to_string(NULL, vm->stack.entries[slot]);
1140                 fprintf(stderr, "  {*%zu} <%p> %s\n", slot, (void *)created, s);
1141                 free(s);
1142         }
1143 
1144         if (prev)
1145                 prev->next = created;
1146         else
1147                 vm->open_upvals = created;
1148 
1149         return created;
1150 }
1151 
1152 static void
1153 uc_vm_close_upvals(uc_vm_t *vm, size_t slot)
1154 {
1155         uc_upvalref_t *ref;
1156 
1157         while (vm->open_upvals && vm->open_upvals->slot >= slot) {
1158                 ref = vm->open_upvals;
1159                 ref->value = ucv_get(vm->stack.entries[ref->slot]);
1160                 ref->closed = true;
1161 
1162                 if (vm->trace) {
1163                         fprintf(stderr, "  {!%zu} <%p> %s\n", ref->slot,
1164                                 (void *)ref,
1165                                 uc_vm_format_val(vm, ref->value));
1166                 }
1167 
1168                 vm->open_upvals = ref->next;
1169                 ucv_put(&ref->header);
1170         }
1171 }
1172 
1173 static void
1174 uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn)
1175 {
1176         uc_callframe_t *frame = uc_vm_current_frame(vm);
1177         uc_function_t *function = uc_program_function_load(uc_vm_current_program(vm), vm->arg.u32);
1178         uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN);
1179         volatile int32_t uv;
1180         size_t i;
1181 
1182         uc_vm_stack_push(vm, &closure->header);
1183 
1184         if (function->module)
1185                 return;
1186 
1187         for (i = 0; i < function->nupvals; i++) {
1188                 uv = (
1189                         frame->ip[0] * 0x1000000 +
1190                         frame->ip[1] * 0x10000 +
1191                         frame->ip[2] * 0x100 +
1192                         frame->ip[3]
1193                 ) - 0x7fffffff;
1194 
1195                 if (uv < 0)
1196                         closure->upvals[i] = uc_vm_capture_upval(vm, frame->stackframe - (uv + 1));
1197                 else
1198                         closure->upvals[i] = frame->closure->upvals[uv];
1199 
1200                 ucv_get(&closure->upvals[i]->header);
1201 
1202                 frame->ip += 4;
1203         }
1204 }
1205 
1206 static void
1207 uc_vm_insn_store_var(uc_vm_t *vm, uc_vm_insn_t insn)
1208 {
1209         uc_value_t *name, *v = uc_vm_stack_pop(vm);
1210         uc_value_t *scope, *next;
1211         bool found;
1212 
1213         scope = vm->globals;
1214         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32);
1215 
1216         while (ucv_type(name) == UC_STRING) {
1217                 ucv_object_get(scope, ucv_string_get(name), &found);
1218 
1219                 if (found)
1220                         break;
1221 
1222                 next = ucv_prototype_get(scope);
1223 
1224                 if (!next) {
1225                         if (uc_vm_is_strict(vm)) {
1226                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1227                                                       "access to undeclared variable %s",
1228                                                       ucv_string_get(name));
1229                         }
1230 
1231                         break;
1232                 }
1233 
1234                 scope = next;
1235         }
1236 
1237         if (scope && ucv_type(name) == UC_STRING)
1238                 ucv_object_add(scope, ucv_string_get(name), ucv_get(v));
1239 
1240         ucv_put(name);
1241         uc_vm_stack_push(vm, v);
1242 }
1243 
1244 static bool
1245 assert_mutable_value(uc_vm_t *vm, uc_value_t *val)
1246 {
1247         if (ucv_is_constant(val)) {
1248                 uc_vm_stack_push(vm, NULL);
1249                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1250                                       "%s value is immutable",
1251                                       ucv_typename(val));
1252 
1253                 return false;
1254         }
1255 
1256         return true;
1257 }
1258 
1259 static void
1260 uc_vm_insn_store_val(uc_vm_t *vm, uc_vm_insn_t insn)
1261 {
1262         uc_value_t *v = uc_vm_stack_pop(vm);
1263         uc_value_t *k = uc_vm_stack_pop(vm);
1264         uc_value_t *o = uc_vm_stack_pop(vm);
1265 
1266         switch (ucv_type(o)) {
1267         case UC_OBJECT:
1268         case UC_ARRAY:
1269                 if (assert_mutable_value(vm, o))
1270                         uc_vm_stack_push(vm, ucv_key_set(vm, o, k, v));
1271 
1272                 break;
1273 
1274         default:
1275                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1276                                       "attempt to set property on %s value",
1277                                       ucv_typename(o));
1278         }
1279 
1280         ucv_put(o);
1281         ucv_put(k);
1282 }
1283 
1284 static void
1285 uc_vm_insn_store_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1286 {
1287         uc_callframe_t *frame = uc_vm_current_frame(vm);
1288         uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32];
1289         uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0));
1290 
1291         if (ref->closed) {
1292                 ucv_put(ref->value);
1293                 ref->value = val;
1294         }
1295         else {
1296                 uc_vm_stack_set(vm, ref->slot, val);
1297         }
1298 }
1299 
1300 static void
1301 uc_vm_insn_store_local(uc_vm_t *vm, uc_vm_insn_t insn)
1302 {
1303         uc_callframe_t *frame = uc_vm_current_frame(vm);
1304         uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0));
1305 
1306         uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val);
1307 }
1308 
1309 static int64_t
1310 int64(uc_value_t *nv, uint64_t *u64)
1311 {
1312         int64_t n;
1313 
1314         n = ucv_int64_get(nv);
1315         *u64 = 0;
1316 
1317         if (errno == ERANGE) {
1318                 n = INT64_MAX;
1319                 *u64 = ucv_uint64_get(nv);
1320         }
1321 
1322         return n;
1323 }
1324 
1325 static uint64_t
1326 abs64(int64_t n)
1327 {
1328         if (n == INT64_MIN)
1329                 return 0x8000000000000000ULL;
1330 
1331         if (n < 0)
1332                 return -n;
1333 
1334         return n;
1335 }
1336 
1337 
1338 static uc_value_t *
1339 uc_vm_value_bitop(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand)
1340 {
1341         uc_value_t *nv1, *nv2, *rv = NULL;
1342         uint64_t u1, u2;
1343         int64_t n1, n2;
1344 
1345         nv1 = ucv_to_number(value);
1346         nv2 = ucv_to_number(operand);
1347 
1348         n1 = int64(nv1, &u1);
1349         n2 = int64(nv2, &u2);
1350 
1351         if (n1 < 0 || n2 < 0) {
1352                 switch (operation) {
1353                 case I_LSHIFT:
1354                         rv = ucv_int64_new(n1 << n2);
1355                         break;
1356 
1357                 case I_RSHIFT:
1358                         rv = ucv_int64_new(n1 >> n2);
1359                         break;
1360 
1361                 case I_BAND:
1362                         rv = ucv_int64_new(n1 & n2);
1363                         break;
1364 
1365                 case I_BXOR:
1366                         rv = ucv_int64_new(n1 ^ n2);
1367                         break;
1368 
1369                 case I_BOR:
1370                         rv = ucv_int64_new(n1 | n2);
1371                         break;
1372 
1373                 default:
1374                         break;
1375                 }
1376         }
1377         else {
1378                 if (!u1) u1 = (uint64_t)n1;
1379                 if (!u2) u2 = (uint64_t)n2;
1380 
1381                 switch (operation) {
1382                 case I_LSHIFT:
1383                         rv = ucv_uint64_new(u1 << (u2 % (sizeof(uint64_t) * CHAR_BIT)));
1384                         break;
1385 
1386                 case I_RSHIFT:
1387                         rv = ucv_uint64_new(u1 >> (u2 % (sizeof(uint64_t) * CHAR_BIT)));
1388                         break;
1389 
1390                 case I_BAND:
1391                         rv = ucv_uint64_new(u1 & u2);
1392                         break;
1393 
1394                 case I_BXOR:
1395                         rv = ucv_uint64_new(u1 ^ u2);
1396                         break;
1397 
1398                 case I_BOR:
1399                         rv = ucv_uint64_new(u1 | u2);
1400                         break;
1401 
1402                 default:
1403                         break;
1404                 }
1405         }
1406 
1407         ucv_put(nv1);
1408         ucv_put(nv2);
1409 
1410         return rv;
1411 }
1412 
1413 static uc_value_t *
1414 uc_vm_string_concat(uc_vm_t *vm, uc_value_t *v1, uc_value_t *v2)
1415 {
1416         char buf[sizeof(void *)], *s1, *s2;
1417         uc_stringbuf_t *sbuf;
1418         size_t l1, l2;
1419 
1420         /* optimize cases for string+string concat... */
1421         if (ucv_type(v1) == UC_STRING && ucv_type(v2) == UC_STRING) {
1422                 s1 = ucv_string_get(v1);
1423                 s2 = ucv_string_get(v2);
1424                 l1 = ucv_string_length(v1);
1425                 l2 = ucv_string_length(v2);
1426 
1427                 /* ... result fits into a tagged pointer */
1428                 if (l1 + l2 + 1 < sizeof(buf)) {
1429                         memcpy(&buf[0], s1, l1);
1430                         memcpy(&buf[l1], s2, l2);
1431 
1432                         return ucv_string_new_length(buf, l1 + l2);
1433                 }
1434         }
1435 
1436         sbuf = ucv_stringbuf_new();
1437 
1438         ucv_to_stringbuf(vm, sbuf, v1, false);
1439         ucv_to_stringbuf(vm, sbuf, v2, false);
1440 
1441         return ucv_stringbuf_finish(sbuf);
1442 }
1443 
1444 static uint64_t
1445 upow64(uint64_t base, uint64_t exponent)
1446 {
1447         uint64_t result = 1;
1448 
1449         while (exponent) {
1450                 if (exponent & 1)
1451                         result *= base;
1452 
1453                 exponent >>= 1;
1454                 base *= base;
1455         }
1456 
1457         return result;
1458 }
1459 
1460 static uc_value_t *
1461 uc_vm_value_arith(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand)
1462 {
1463         uc_value_t *nv1, *nv2, *rv = NULL;
1464         uint64_t u1, u2;
1465         int64_t n1, n2;
1466         double d1, d2;
1467 
1468         if (operation == I_LSHIFT || operation == I_RSHIFT ||
1469             operation == I_BAND || operation == I_BXOR || operation == I_BOR)
1470                 return uc_vm_value_bitop(vm, operation, value, operand);
1471 
1472         if (operation == I_ADD && (ucv_type(value) == UC_STRING || ucv_type(operand) == UC_STRING))
1473                 return uc_vm_string_concat(vm, value, operand);
1474 
1475         nv1 = ucv_to_number(value);
1476         nv2 = ucv_to_number(operand);
1477 
1478         /* any operation involving NaN results in NaN */
1479         if (!nv1 || !nv2) {
1480                 ucv_put(nv1);
1481                 ucv_put(nv2);
1482 
1483                 return ucv_double_new(NAN);
1484         }
1485         if (ucv_type(nv1) == UC_DOUBLE || ucv_type(nv2) == UC_DOUBLE) {
1486                 d1 = ucv_double_get(nv1);
1487                 d2 = ucv_double_get(nv2);
1488 
1489                 switch (operation) {
1490                 case I_ADD:
1491                 case I_PLUS:
1492                         rv = ucv_double_new(d1 + d2);
1493                         break;
1494 
1495                 case I_SUB:
1496                 case I_MINUS:
1497                         rv = ucv_double_new(d1 - d2);
1498                         break;
1499 
1500                 case I_MUL:
1501                         rv = ucv_double_new(d1 * d2);
1502                         break;
1503 
1504                 case I_DIV:
1505                         if (d2 == 0.0)
1506                                 rv = ucv_double_new(INFINITY);
1507                         else if (isnan(d2))
1508                                 rv = ucv_double_new(NAN);
1509                         else if (!isfinite(d2))
1510                                 rv = ucv_double_new(isfinite(d1) ? 0.0 : NAN);
1511                         else
1512                                 rv = ucv_double_new(d1 / d2);
1513 
1514                         break;
1515 
1516                 case I_MOD:
1517                         rv = ucv_double_new(fmod(d1, d2));
1518                         break;
1519 
1520                 case I_EXP:
1521                         rv = ucv_double_new(pow(d1, d2));
1522                         break;
1523 
1524                 default:
1525                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1526                                               "undefined arithmetic operation %d",
1527                                               operation);
1528                         break;
1529                 }
1530         }
1531         else {
1532                 n1 = int64(nv1, &u1);
1533                 n2 = int64(nv2, &u2);
1534 
1535                 switch (operation) {
1536                 case I_ADD:
1537                 case I_PLUS:
1538                         if (n1 < 0 || n2 < 0) {
1539                                 if (u1)
1540                                         rv = ucv_uint64_new(u1 - abs64(n2));
1541                                 else if (u2)
1542                                         rv = ucv_uint64_new(u2 - abs64(n1));
1543                                 else
1544                                         rv = ucv_int64_new(n1 + n2);
1545                         }
1546                         else {
1547                                 if (!u1) u1 = (uint64_t)n1;
1548                                 if (!u2) u2 = (uint64_t)n2;
1549 
1550                                 rv = ucv_uint64_new(u1 + u2);
1551                         }
1552 
1553                         break;
1554 
1555                 case I_SUB:
1556                 case I_MINUS:
1557                         if (n1 < 0 && n2 < 0) {
1558                                 if (n1 > n2)
1559                                         rv = ucv_uint64_new(abs64(n2) - abs64(n1));
1560                                 else
1561                                         rv = ucv_int64_new(n1 - n2);
1562                         }
1563                         else if (n1 >= 0 && n2 >= 0) {
1564                                 if (!u1) u1 = (uint64_t)n1;
1565                                 if (!u2) u2 = (uint64_t)n2;
1566 
1567                                 if (u2 > u1)
1568                                         rv = ucv_int64_new(-(u2 - u1));
1569                                 else
1570                                         rv = ucv_uint64_new(u1 - u2);
1571                         }
1572                         else if (n1 >= 0) {
1573                                 if (!u1) u1 = (uint64_t)n1;
1574 
1575                                 rv = ucv_uint64_new(u1 + abs64(n2));
1576                         }
1577                         else {
1578                                 rv = ucv_int64_new(n1 - n2);
1579                         }
1580 
1581                         break;
1582 
1583                 case I_MUL:
1584                         if (n1 < 0 && n2 < 0) {
1585                                 rv = ucv_uint64_new(abs64(n1) * abs64(n2));
1586                         }
1587                         else if (n1 >= 0 && n2 >= 0) {
1588                                 if (!u1) u1 = (uint64_t)n1;
1589                                 if (!u2) u2 = (uint64_t)n2;
1590 
1591                                 rv = ucv_uint64_new(u1 * u2);
1592                         }
1593                         else {
1594                                 rv = ucv_int64_new(n1 * n2);
1595                         }
1596 
1597                         break;
1598 
1599                 case I_DIV:
1600                         if (n2 == 0) {
1601                                 rv = ucv_double_new(INFINITY);
1602                         }
1603                         else if (n1 < 0 || n2 < 0) {
1604                                 rv = ucv_int64_new(n1 / n2);
1605                         }
1606                         else {
1607                                 if (!u1) u1 = (uint64_t)n1;
1608                                 if (!u2) u2 = (uint64_t)n2;
1609 
1610                                 rv = ucv_uint64_new(u1 / u2);
1611                         }
1612 
1613                         break;
1614 
1615                 case I_MOD:
1616                         if (n1 < 0 || n2 < 0) {
1617                                 rv = ucv_int64_new(n1 % n2);
1618                         }
1619                         else {
1620                                 if (!u1) u1 = (uint64_t)n1;
1621                                 if (!u2) u2 = (uint64_t)n2;
1622 
1623                                 rv = ucv_uint64_new(u1 % u2);
1624                         }
1625 
1626                         break;
1627 
1628                 case I_EXP:
1629                         if (n1 < 0 || n2 < 0) {
1630                                 if (n1 < 0 && n2 < 0)
1631                                         rv = ucv_double_new(-(1.0 / (double)upow64(abs64(n1), abs64(n2))));
1632                                 else if (n2 < 0)
1633                                         rv = ucv_double_new(1.0 / (double)upow64(abs64(n1), abs64(n2)));
1634                                 else
1635                                         rv = ucv_int64_new(-upow64(abs64(n1), abs64(n2)));
1636                         }
1637                         else {
1638                                 if (!u1) u1 = (uint64_t)n1;
1639                                 if (!u2) u2 = (uint64_t)n2;
1640 
1641                                 rv = ucv_uint64_new(upow64(u1, u2));
1642                         }
1643 
1644                         break;
1645 
1646                 default:
1647                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1648                                               "undefined arithmetic operation %d",
1649                                               operation);
1650                         break;
1651                 }
1652         }
1653 
1654         ucv_put(nv1);
1655         ucv_put(nv2);
1656 
1657         return rv;
1658 }
1659 
1660 static void
1661 uc_vm_insn_update_var(uc_vm_t *vm, uc_vm_insn_t insn)
1662 {
1663         uc_value_t *name, *val = NULL, *inc = uc_vm_stack_pop(vm);
1664         uc_value_t *scope, *next;
1665         bool found;
1666 
1667         scope = vm->globals;
1668         name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32 & 0x00FFFFFF);
1669 
1670         assert(ucv_type(name) == UC_STRING);
1671 
1672         while (true) {
1673                 val = ucv_object_get(scope, ucv_string_get(name), &found);
1674 
1675                 if (found)
1676                         break;
1677 
1678                 next = ucv_prototype_get(scope);
1679 
1680                 if (!next) {
1681                         if (uc_vm_is_strict(vm)) {
1682                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1683                                                       "access to undeclared variable %s",
1684                                                       ucv_string_get(name));
1685                         }
1686 
1687                         break;
1688                 }
1689 
1690                 scope = next;
1691         }
1692 
1693         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc);
1694 
1695         ucv_object_add(scope, ucv_string_get(name), ucv_get(val));
1696         uc_vm_stack_push(vm, val);
1697 
1698         ucv_put(name);
1699         ucv_put(inc);
1700 }
1701 
1702 static void
1703 uc_vm_insn_update_val(uc_vm_t *vm, uc_vm_insn_t insn)
1704 {
1705         uc_value_t *inc = uc_vm_stack_pop(vm);
1706         uc_value_t *k = uc_vm_stack_pop(vm);
1707         uc_value_t *v = uc_vm_stack_pop(vm);
1708         uc_value_t *val = NULL;
1709 
1710         switch (ucv_type(v)) {
1711         case UC_OBJECT:
1712         case UC_ARRAY:
1713                 if (assert_mutable_value(vm, v)) {
1714                         val = ucv_key_get(vm, v, k);
1715                         uc_vm_stack_push(vm, ucv_key_set(vm, v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc)));
1716                 }
1717 
1718                 break;
1719 
1720         default:
1721                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
1722                                       "left-hand side expression is %s",
1723                                       v ? "not an array or object" : "null");
1724 
1725                 break;
1726         }
1727 
1728         ucv_put(val);
1729         ucv_put(inc);
1730         ucv_put(v);
1731         ucv_put(k);
1732 }
1733 
1734 static void
1735 uc_vm_insn_update_upval(uc_vm_t *vm, uc_vm_insn_t insn)
1736 {
1737         uc_callframe_t *frame = uc_vm_current_frame(vm);
1738         size_t slot = vm->arg.u32 & 0x00FFFFFF;
1739         uc_upvalref_t *ref = frame->closure->upvals[slot];
1740         uc_value_t *inc = uc_vm_stack_pop(vm);
1741         uc_value_t *val;
1742 
1743         if (ref->closed)
1744                 val = ref->value;
1745         else
1746                 val = vm->stack.entries[ref->slot];
1747 
1748         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc);
1749 
1750         uc_vm_stack_push(vm, val);
1751 
1752         ucv_put(inc);
1753 
1754         if (ref->closed) {
1755                 ucv_put(ref->value);
1756                 ref->value = ucv_get(uc_vm_stack_peek(vm, 0));
1757         }
1758         else {
1759                 uc_vm_stack_set(vm, ref->slot, ucv_get(uc_vm_stack_peek(vm, 0)));
1760         }
1761 }
1762 
1763 static void
1764 uc_vm_insn_update_local(uc_vm_t *vm, uc_vm_insn_t insn)
1765 {
1766         uc_callframe_t *frame = uc_vm_current_frame(vm);
1767         size_t slot = vm->arg.u32 & 0x00FFFFFF;
1768         uc_value_t *inc = uc_vm_stack_pop(vm);
1769         uc_value_t *val;
1770 
1771         val = uc_vm_value_arith(vm, vm->arg.u32 >> 24,
1772                                 vm->stack.entries[frame->stackframe + slot], inc);
1773 
1774         uc_vm_stack_push(vm, val);
1775 
1776         ucv_put(inc);
1777         uc_vm_stack_set(vm, frame->stackframe + slot, ucv_get(uc_vm_stack_peek(vm, 0)));
1778 }
1779 
1780 static void
1781 uc_vm_insn_narr(uc_vm_t *vm, uc_vm_insn_t insn)
1782 {
1783         uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32);
1784 
1785         uc_vm_stack_push(vm, arr);
1786 }
1787 
1788 static void
1789 uc_vm_insn_parr(uc_vm_t *vm, uc_vm_insn_t insn)
1790 {
1791         uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32);
1792         size_t idx;
1793 
1794         for (idx = 0; idx < vm->arg.u32; idx++)
1795                 ucv_array_push(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1));
1796 
1797         for (idx = 0; idx < vm->arg.u32; idx++)
1798                 uc_vm_stack_pop(vm);
1799 
1800         //uc_vm_shrink(state, vm->arg.u32);
1801 }
1802 
1803 static void
1804 uc_vm_insn_marr(uc_vm_t *vm, uc_vm_insn_t insn)
1805 {
1806         uc_value_t *src = uc_vm_stack_pop(vm);
1807         uc_value_t *dst = uc_vm_stack_peek(vm, 0);
1808         size_t i;
1809         char *s;
1810 
1811         if (ucv_type(src) != UC_ARRAY) {
1812                 s = ucv_to_string(vm, src);
1813                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s);
1814                 ucv_put(src);
1815                 free(s);
1816 
1817                 return;
1818         }
1819 
1820         for (i = 0; i < ucv_array_length(src); i++)
1821                 ucv_array_push(dst, ucv_get(ucv_array_get(src, i)));
1822 
1823         ucv_put(src);
1824 }
1825 
1826 static void
1827 uc_vm_insn_nobj(uc_vm_t *vm, uc_vm_insn_t insn)
1828 {
1829         uc_value_t *obj = ucv_object_new(vm);
1830 
1831         uc_vm_stack_push(vm, obj);
1832 }
1833 
1834 static void
1835 uc_vm_insn_sobj(uc_vm_t *vm, uc_vm_insn_t insn)
1836 {
1837         uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32);
1838         size_t idx;
1839 
1840         for (idx = 0; idx < vm->arg.u32; idx += 2)
1841                 ucv_key_set(vm, obj,
1842                         uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1),
1843                         uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2));
1844 
1845         for (idx = 0; idx < vm->arg.u32; idx++)
1846                 ucv_put(uc_vm_stack_pop(vm));
1847 }
1848 
1849 static void
1850 uc_vm_insn_mobj(uc_vm_t *vm, uc_vm_insn_t insn)
1851 {
1852         uc_value_t *src = uc_vm_stack_pop(vm);
1853         uc_value_t *dst = uc_vm_stack_peek(vm, 0);
1854         size_t i;
1855         char *s;
1856 
1857         switch (ucv_type(src)) {
1858         case UC_OBJECT:
1859                 ; /* a label can only be part of a statement and a declaration is not a statement */
1860                 ucv_object_foreach(src, k, v)
1861                         ucv_object_add(dst, k, ucv_get(v));
1862 
1863                 ucv_put(src);
1864                 break;
1865 
1866         case json_type_array:
1867                 for (i = 0; i < ucv_array_length(src); i++) {
1868                         xasprintf(&s, "%zu", i);
1869                         ucv_object_add(dst, s, ucv_get(ucv_array_get(src, i)));
1870                         free(s);
1871                 }
1872 
1873                 ucv_put(src);
1874                 break;
1875 
1876         default:
1877                 s = ucv_to_string(vm, src);
1878                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Value (%s) is not iterable", s);
1879                 free(s);
1880 
1881                 break;
1882         }
1883 }
1884 
1885 static void
1886 uc_vm_insn_arith(uc_vm_t *vm, uc_vm_insn_t insn)
1887 {
1888         uc_value_t *r2 = uc_vm_stack_pop(vm);
1889         uc_value_t *r1 = uc_vm_stack_pop(vm);
1890         uc_value_t *rv;
1891 
1892         rv = uc_vm_value_arith(vm, insn, r1, r2);
1893 
1894         ucv_put(r1);
1895         ucv_put(r2);
1896 
1897         uc_vm_stack_push(vm, rv);
1898 }
1899 
1900 static void
1901 uc_vm_insn_plus_minus(uc_vm_t *vm, uc_vm_insn_t insn)
1902 {
1903         uc_value_t *v = uc_vm_stack_pop(vm), *nv;
1904         bool is_sub = (insn == I_MINUS);
1905         int64_t n;
1906         double d;
1907 
1908         if (ucv_type(v) == UC_STRING) {
1909                 nv = uc_number_parse(ucv_string_get(v), NULL);
1910 
1911                 if (nv) {
1912                         ucv_put(v);
1913                         v = nv;
1914                 }
1915         }
1916 
1917         switch (ucv_type(v)) {
1918         case UC_INTEGER:
1919                 n = ucv_int64_get(v);
1920 
1921                 /* numeric value is in range 9223372036854775808..18446744073709551615 */
1922                 if (errno == ERANGE) {
1923                         if (is_sub)
1924                                 /* make negation of large numeric value result in smallest negative value */
1925                                 uc_vm_stack_push(vm, ucv_int64_new(INT64_MIN));
1926                         else
1927                                 /* for positive number coercion return value as-is */
1928                                 uc_vm_stack_push(vm, ucv_get(v));
1929                 }
1930 
1931                 /* numeric value is in range -9223372036854775808..9223372036854775807 */
1932                 else {
1933                         if (is_sub) {
1934                                 if (n == INT64_MIN)
1935                                         /* make negation of minimum value result in maximum signed positive value */
1936                                         uc_vm_stack_push(vm, ucv_int64_new(INT64_MAX));
1937                                 else
1938                                         /* for all other values flip the sign */
1939                                         uc_vm_stack_push(vm, ucv_int64_new(-n));
1940                         }
1941                         else {
1942                                 /* for positive number coercion return value as-is */
1943                                 uc_vm_stack_push(vm, ucv_get(v));
1944                         }
1945                 }
1946 
1947                 break;
1948 
1949         case UC_DOUBLE:
1950                 d = ucv_double_get(v);
1951                 uc_vm_stack_push(vm, ucv_double_new(is_sub ? -d : d));
1952                 break;
1953 
1954         case UC_BOOLEAN:
1955                 n = (int64_t)ucv_boolean_get(v);
1956                 uc_vm_stack_push(vm, ucv_int64_new(is_sub ? -n : n));
1957                 break;
1958 
1959         case UC_NULL:
1960                 uc_vm_stack_push(vm, ucv_int64_new(0));
1961                 break;
1962 
1963         default:
1964                 uc_vm_stack_push(vm, ucv_double_new(NAN));
1965         }
1966 
1967         ucv_put(v);
1968 }
1969 
1970 static void
1971 uc_vm_insn_bitop(uc_vm_t *vm, uc_vm_insn_t insn)
1972 {
1973         uc_value_t *r2 = uc_vm_stack_pop(vm);
1974         uc_value_t *r1 = uc_vm_stack_pop(vm);
1975         uc_value_t *rv;
1976 
1977         rv = uc_vm_value_bitop(vm, insn, r1, r2);
1978 
1979         ucv_put(r1);
1980         ucv_put(r2);
1981 
1982         uc_vm_stack_push(vm, rv);
1983 }
1984 
1985 static void
1986 uc_vm_insn_complement(uc_vm_t *vm, uc_vm_insn_t insn)
1987 {
1988         uc_value_t *v = uc_vm_stack_pop(vm);
1989         uc_value_t *nv;
1990         uint64_t u;
1991         int64_t n;
1992 
1993         nv = ucv_to_number(v);
1994         n = int64(nv, &u);
1995 
1996         if (n < 0) {
1997                 uc_vm_stack_push(vm, ucv_int64_new(~n));
1998         }
1999         else {
2000                 if (!u) u = (uint64_t)n;
2001 
2002                 uc_vm_stack_push(vm, ucv_uint64_new(~u));
2003         }
2004 
2005         ucv_put(nv);
2006         ucv_put(v);
2007 }
2008 
2009 static void
2010 uc_vm_insn_rel(uc_vm_t *vm, uc_vm_insn_t insn)
2011 {
2012         uc_value_t *r2 = uc_vm_stack_pop(vm);
2013         uc_value_t *r1 = uc_vm_stack_pop(vm);
2014 
2015         bool res = ucv_compare(insn, r1, r2, NULL);
2016 
2017         ucv_put(r1);
2018         ucv_put(r2);
2019 
2020         uc_vm_stack_push(vm, ucv_boolean_new(res));
2021 }
2022 
2023 static void
2024 uc_vm_insn_in(uc_vm_t *vm, uc_vm_insn_t insn)
2025 {
2026         uc_value_t *r2 = uc_vm_stack_pop(vm);
2027         uc_value_t *r1 = uc_vm_stack_pop(vm);
2028         uc_value_t *item;
2029         size_t arrlen, arridx;
2030         bool found = false;
2031         char *key;
2032 
2033         switch (ucv_type(r2)) {
2034         case UC_ARRAY:
2035                 for (arridx = 0, arrlen = ucv_array_length(r2);
2036                      arridx < arrlen; arridx++) {
2037                         item = ucv_array_get(r2, arridx);
2038 
2039                         if (ucv_compare(I_EQ, r1, item, NULL)) {
2040                                 found = true;
2041                                 break;
2042                         }
2043                 }
2044 
2045                 break;
2046 
2047         case UC_OBJECT:
2048                 if (ucv_type(r1) == UC_STRING) {
2049                         ucv_object_get(r2, ucv_string_get(r1), &found);
2050                 }
2051                 else {
2052                         key = ucv_to_string(vm, r1);
2053                         ucv_object_get(r2, key, &found);
2054                         free(key);
2055                 }
2056 
2057                 break;
2058 
2059         default:
2060                 found = false;
2061         }
2062 
2063         ucv_put(r1);
2064         ucv_put(r2);
2065 
2066         uc_vm_stack_push(vm, ucv_boolean_new(found));
2067 }
2068 
2069 static void
2070 uc_vm_insn_equality(uc_vm_t *vm, uc_vm_insn_t insn)
2071 {
2072         uc_value_t *r2 = uc_vm_stack_pop(vm);
2073         uc_value_t *r1 = uc_vm_stack_pop(vm);
2074         bool equal;
2075 
2076         if (ucv_is_scalar(r1) && ucv_is_scalar(r2))
2077                 equal = ucv_is_equal(r1, r2);
2078         else
2079                 equal = (r1 == r2);
2080 
2081         ucv_put(r1);
2082         ucv_put(r2);
2083 
2084         uc_vm_stack_push(vm, ucv_boolean_new((insn == I_EQS) ? equal : !equal));
2085 }
2086 
2087 static void
2088 uc_vm_insn_not(uc_vm_t *vm, uc_vm_insn_t insn)
2089 {
2090         uc_value_t *r1 = uc_vm_stack_pop(vm);
2091 
2092         uc_vm_stack_push(vm, ucv_boolean_new(!ucv_is_truish(r1)));
2093         ucv_put(r1);
2094 }
2095 
2096 static void
2097 uc_vm_insn_jmp(uc_vm_t *vm, uc_vm_insn_t insn)
2098 {
2099         uc_callframe_t *frame = uc_vm_current_frame(vm);
2100         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
2101         int32_t addr = vm->arg.s32;
2102 
2103         /* ip already has been incremented */
2104         addr -= 5;
2105 
2106         if (frame->ip + addr < chunk->entries ||
2107             frame->ip + addr >= chunk->entries + chunk->count) {
2108                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
2109                 return;
2110         }
2111 
2112         frame->ip += addr;
2113 }
2114 
2115 static void
2116 uc_vm_insn_jmpz(uc_vm_t *vm, uc_vm_insn_t insn)
2117 {
2118         uc_callframe_t *frame = uc_vm_current_frame(vm);
2119         uc_chunk_t *chunk = uc_vm_frame_chunk(frame);
2120         uc_value_t *v = uc_vm_stack_pop(vm);
2121         int32_t addr = vm->arg.s32;
2122 
2123         /* ip already has been incremented */
2124         addr -= 5;
2125 
2126         if (frame->ip + addr < chunk->entries ||
2127             frame->ip + addr >= chunk->entries + chunk->count) {
2128                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range");
2129                 return;
2130         }
2131 
2132         if (!ucv_is_truish(v))
2133                 frame->ip += addr;
2134 
2135         ucv_put(v);
2136 }
2137 
2138 static void
2139 uc_vm_insn_next(uc_vm_t *vm, uc_vm_insn_t insn)
2140 {
2141         uc_value_t *k = uc_vm_stack_pop(vm);
2142         uc_value_t *v = uc_vm_stack_pop(vm);
2143         void *end = (void *)~(uintptr_t)0;
2144         uc_resource_t *iterk;
2145         struct lh_entry *curr;
2146         uint64_t n;
2147 
2148         if (k != NULL && ucv_type(k) != UC_RESOURCE) {
2149                 fprintf(stderr, "Invalid iterator value\n");
2150                 abort();
2151         }
2152 
2153         if (k == NULL)
2154                 k = ucv_resource_new(NULL, NULL);
2155 
2156         iterk = (uc_resource_t *)k;
2157 
2158         switch (ucv_type(v)) {
2159         case UC_OBJECT:
2160                 curr = iterk->data ? iterk->data : ((uc_object_t *)v)->table->head;
2161 
2162                 if (curr != NULL && curr != end) {
2163                         iterk->data = curr->next ? curr->next : end;
2164 
2165                         uc_vm_stack_push(vm, ucv_string_new(curr->k));
2166 
2167                         if (insn == I_NEXTKV)
2168                                 uc_vm_stack_push(vm, ucv_get((uc_value_t *)curr->v));
2169 
2170                         uc_vm_stack_push(vm, k);
2171                         ucv_put(v);
2172 
2173                         return;
2174                 }
2175 
2176                 break;
2177 
2178         case UC_ARRAY:
2179                 n = (uintptr_t)iterk->data;
2180 
2181                 if (n < ucv_array_length(v)) {
2182                         iterk->data = (void *)(uintptr_t)(n + 1);
2183 
2184                         if (insn == I_NEXTKV)
2185                                 uc_vm_stack_push(vm, ucv_uint64_new(n));
2186 
2187                         uc_vm_stack_push(vm, ucv_get(ucv_array_get(v, n)));
2188 
2189                         uc_vm_stack_push(vm, k);
2190                         ucv_put(v);
2191 
2192                         return;
2193                 }
2194 
2195                 break;
2196 
2197         default:
2198                 break;
2199         }
2200 
2201         uc_vm_stack_push(vm, NULL);
2202         uc_vm_stack_push(vm, NULL);
2203 
2204         if (insn == I_NEXTKV)
2205                 uc_vm_stack_push(vm, NULL);
2206 
2207         ucv_put(k);
2208         ucv_put(v);
2209 }
2210 
2211 static void
2212 uc_vm_insn_close_upval(uc_vm_t *vm, uc_vm_insn_t insn)
2213 {
2214         uc_vm_close_upvals(vm, vm->stack.count - 1);
2215         ucv_put(uc_vm_stack_pop(vm));
2216 }
2217 
2218 static void
2219 uc_vm_skip_call(uc_vm_t *vm, bool mcall)
2220 {
2221         uc_callframe_t *frame = uc_vm_current_frame(vm);
2222         size_t i;
2223 
2224         /* pop all function arguments, the function itself and the associated
2225          * function context off the stack */
2226         for (i = 0; i < 1 + mcall + (vm->arg.u32 & 0xffff); i++)
2227                 ucv_put(uc_vm_stack_pop(vm));
2228 
2229         /* skip all encoded spread value indexes */
2230         for (i = 0; i < (vm->arg.u32 >> 16); i++)
2231                 frame->ip += 2;
2232 
2233         uc_vm_stack_push(vm, NULL);
2234 }
2235 
2236 static void
2237 uc_vm_insn_call(uc_vm_t *vm, uc_vm_insn_t insn)
2238 {
2239         uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff));
2240         uc_value_t *ctx = NULL;
2241 
2242         if (!ucv_is_callable(fno) && insn == I_QCALL)
2243                 return uc_vm_skip_call(vm, false);
2244 
2245         if (!ucv_is_arrowfn(fno))
2246                 ctx = NULL;
2247         else if (vm->callframes.count > 0)
2248                 ctx = uc_vm_current_frame(vm)->ctx;
2249 
2250         uc_vm_call_function(vm, ucv_get(ctx), fno, false, vm->arg.u32);
2251 }
2252 
2253 static void
2254 uc_vm_insn_mcall(uc_vm_t *vm, uc_vm_insn_t insn)
2255 {
2256         size_t key_slot = vm->stack.count - (vm->arg.u32 & 0xffff) - 1;
2257         uc_value_t *ctx = vm->stack.entries[key_slot - 1];
2258         uc_value_t *key = vm->stack.entries[key_slot];
2259         uc_value_t *fno = uc_vm_resolve_upval(vm, ucv_key_get(vm, ctx, key));
2260 
2261         if (!ucv_is_callable(fno) && insn == I_QMCALL)
2262                 return uc_vm_skip_call(vm, true);
2263 
2264         uc_vm_stack_set(vm, key_slot, fno);
2265 
2266         /* arrow functions as method calls inherit the parent ctx */
2267         if (ucv_is_arrowfn(fno))
2268                 ctx = uc_vm_current_frame(vm)->ctx;
2269 
2270         uc_vm_call_function(vm, ucv_get(ctx), ucv_get(fno), true, vm->arg.u32);
2271 }
2272 
2273 static void
2274 uc_vm_insn_print(uc_vm_t *vm, uc_vm_insn_t insn)
2275 {
2276         uc_value_t *v = uc_vm_stack_pop(vm);
2277         char *p;
2278 
2279         switch (ucv_type(v)) {
2280         case UC_OBJECT:
2281         case UC_ARRAY:
2282                 p = ucv_to_jsonstring(vm, v);
2283                 fwrite(p, 1, strlen(p), vm->output);
2284                 free(p);
2285                 break;
2286 
2287         case UC_STRING:
2288                 fwrite(ucv_string_get(v), 1, ucv_string_length(v), vm->output);
2289                 break;
2290 
2291         case UC_NULL:
2292                 break;
2293 
2294         default:
2295                 p = ucv_to_string(vm, v);
2296                 fwrite(p, 1, strlen(p), vm->output);
2297                 free(p);
2298         }
2299 
2300         ucv_put(v);
2301 }
2302 
2303 static void
2304 uc_vm_insn_delete(uc_vm_t *vm, uc_vm_insn_t insn)
2305 {
2306         uc_value_t *k = uc_vm_stack_pop(vm);
2307         uc_value_t *v = uc_vm_stack_pop(vm);
2308         bool rv;
2309 
2310         switch (ucv_type(v)) {
2311         case UC_OBJECT:
2312                 if (assert_mutable_value(vm, v)) {
2313                         rv = ucv_key_delete(vm, v, k);
2314                         uc_vm_stack_push(vm, ucv_boolean_new(rv));
2315                 }
2316 
2317                 break;
2318 
2319         default:
2320                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
2321                                       "left-hand side expression is %s",
2322                                       v ? "not an object" : "null");
2323 
2324                 break;
2325         }
2326 
2327         ucv_put(k);
2328         ucv_put(v);
2329 }
2330 
2331 static void
2332 uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
2333 {
2334         uc_callframe_t *frame = uc_vm_current_frame(vm);
2335         uc_program_t *prog = uc_vm_current_program(vm);
2336         uint16_t from = vm->arg.u32 & 0xffff;
2337         uint16_t to = vm->arg.u32 >> 16;
2338         uc_value_t *name, *modobj;
2339         uint32_t cidx;
2340 
2341         /* is a wildcard import * from ... */
2342         if (to == 0xffff) {
2343                 to = from;
2344                 modobj = ucv_object_new(vm);
2345 
2346                 /* instruction is followed by u16 containing the offset of the
2347                  * first module export and `from` times u32 values containing
2348                  * the constant indexes of the names */
2349                 for (from = frame->ip[0] * 0x100 + frame->ip[1], frame->ip += 2;
2350                      from < prog->exports.count && to > 0;
2351                      from++, to--) {
2352 
2353                         cidx = (
2354                                 frame->ip[0] * 0x1000000UL +
2355                                 frame->ip[1] * 0x10000UL +
2356                                 frame->ip[2] * 0x100UL +
2357                                 frame->ip[3]
2358                         );
2359 
2360                         frame->ip += 4;
2361 
2362                         name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
2363 
2364                         if (ucv_type(name) == UC_STRING && prog->exports.entries[from])
2365                                 ucv_object_add(modobj, ucv_string_get(name),
2366                                         ucv_get(&prog->exports.entries[from]->header));
2367 
2368                         ucv_put(name);
2369                 }
2370 
2371                 ucv_set_constant(modobj, true);
2372 
2373                 uc_vm_stack_push(vm, modobj);
2374         }
2375 
2376         /* module export available, patch into upvalue */
2377         else if (from <= prog->exports.count && prog->exports.entries[from]) {
2378                 frame->closure->upvals[to] = prog->exports.entries[from];
2379                 ucv_get(&prog->exports.entries[from]->header);
2380         }
2381 
2382         /* module export missing, e.g. due to premature return in module,
2383          * patch up dummy upvalue ref with `null` value */
2384         else {
2385                 frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0);
2386                 frame->closure->upvals[to]->closed = true;
2387         }
2388 }
2389 
2390 static void
2391 uc_vm_insn_export(uc_vm_t *vm, uc_vm_insn_t insn)
2392 {
2393         uc_callframe_t *frame = uc_vm_current_frame(vm);
2394         uc_program_t *prog = uc_vm_current_program(vm);
2395         uc_upvalref_t *ref = uc_vm_capture_upval(vm, frame->stackframe + vm->arg.u32);
2396 
2397         uc_vector_push(&prog->exports, ref);
2398         ucv_get(&ref->header);
2399 }
2400 
2401 static void
2402 uc_vm_insn_dynload(uc_vm_t *vm, uc_vm_insn_t insn)
2403 {
2404         uc_callframe_t *frame = uc_vm_current_frame(vm);
2405         uc_value_t *name, *export, *modscope, *modobj;
2406         uint16_t count = vm->arg.u32 & 0xffff;
2407         uint16_t to = vm->arg.u32 >> 16;
2408         uint32_t cidx;
2409         bool found;
2410 
2411         /* instruction is followed by u32 containing the constant index of the
2412          * module name string to import and `count` times u32 values containing
2413          * the import name constant indexes */
2414 
2415         cidx = (
2416                 frame->ip[0] * 0x1000000UL +
2417                 frame->ip[1] * 0x10000UL +
2418                 frame->ip[2] * 0x100UL +
2419                 frame->ip[3]
2420         );
2421 
2422         frame->ip += 4;
2423 
2424         /* push module name onto stack, then attempt to load module and pop
2425          * name value again. Will raise exception on error */
2426         name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
2427         modscope = uc_require_library(vm, name, true);
2428         ucv_put(name);
2429 
2430         if (!modscope)
2431                 return;
2432 
2433         /* If count is zero, we're doing a wildcard import. Shallow copy module
2434          * object, mark it constant and patch into the target upvalue. */
2435         if (count == 0) {
2436                 modobj = ucv_object_new(vm);
2437 
2438                 ucv_object_foreach(modscope, k, v)
2439                         ucv_object_add(modobj, k, ucv_get(v));
2440 
2441                 ucv_set_constant(modobj, true);
2442 
2443                 uc_vm_stack_push(vm, modobj);
2444         }
2445 
2446         /* ... otherwise we're importing a specific list of names */
2447         else {
2448                 while (count > 0) {
2449                         cidx = (
2450                                 frame->ip[0] * 0x1000000UL +
2451                                 frame->ip[1] * 0x10000UL +
2452                                 frame->ip[2] * 0x100UL +
2453                                 frame->ip[3]
2454                         );
2455 
2456                         frame->ip += 4;
2457 
2458                         name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
2459                         export = ucv_object_get(modscope, ucv_string_get(name), &found);
2460 
2461                         if (!found) {
2462                                 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE,
2463                                                       "Module does not export %s",
2464                                                       ucv_string_get(name));
2465 
2466                                 ucv_put(name);
2467 
2468                                 return;
2469                         }
2470 
2471                         ucv_put(name);
2472 
2473                         frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0);
2474                         frame->closure->upvals[to]->closed = true;
2475                         frame->closure->upvals[to]->value = ucv_get(export);
2476 
2477                         count--;
2478                         to++;
2479                 }
2480         }
2481 }
2482 
2483 static void
2484 uc_vm_gc_step(uc_vm_t *vm)
2485 {
2486         size_t curr_count = 0, prev_count = 0;
2487         uc_weakref_t *ref;
2488 
2489         if (!(vm->gc_flags & GC_ENABLED))
2490                 return;
2491 
2492         if (vm->alloc_refs >= vm->gc_interval) {
2493                 if (vm->trace) {
2494                         for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
2495                                 prev_count++;
2496 
2497                         ucv_gc(vm);
2498 
2499                         for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
2500                                 curr_count++;
2501 
2502                         fprintf(stderr, "! GC reclaimed %zu object(s)\n", prev_count - curr_count);
2503                 }
2504                 else {
2505                         ucv_gc(vm);
2506                 }
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