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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt