• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/vm.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt