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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt