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 <assert.h> 18 #include <math.h> 19 #include <errno.h> 20 #include <limits.h> 21 #include <fcntl.h> 22 #include <unistd.h> 23 24 #include "ucode/internal/vm.h" /* ISA: I_*, uc_vm_insn_t, __insns */ 25 #include "ucode/internal/program.h" 26 #include "ucode/internal/chunk.h" 27 #include "ucode/internal/lib.h" /* uc_error_context_format() */ 28 #include "ucode/internal/platform.h" 29 30 #undef __insn 31 #define __insn(_name) #_name, 32 33 static const char *insn_names[__I_MAX] = { 34 __insns 35 }; 36 37 const int8_t uc_vm_insn_format[__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 [I_JMPNT] = 4, 70 71 [I_COPY] = 1, 72 73 [I_CALL] = 4, 74 75 [I_IMPORT] = 4, 76 [I_EXPORT] = 4, 77 [I_DYNLOAD] = 4 78 }; 79 80 const char *exception_type_strings[] = { 81 [EXCEPTION_SYNTAX] = "Syntax error", 82 [EXCEPTION_RUNTIME] = "Runtime error", 83 [EXCEPTION_TYPE] = "Type error", 84 [EXCEPTION_REFERENCE] = "Reference error", 85 [EXCEPTION_USER] = "Error", 86 [EXCEPTION_EXIT] = "Exit" 87 }; 88 89 90 static const char * 91 uc_vm_insn_to_name(uc_vm_insn_t insn) 92 { 93 if (insn < 0 || insn >= __I_MAX) 94 return "(unknown)"; 95 96 return insn_names[insn]; 97 } 98 99 int8_t 100 uc_vm_insn_to_argtype(uc_vm_insn_t insn) 101 { 102 if (insn < 0 || insn >= __I_MAX) 103 return 0; 104 105 return uc_vm_insn_format[insn]; 106 } 107 108 static void 109 uc_vm_reset_stack(uc_vm_t *vm) 110 { 111 while (vm->stack.count > 0) { 112 vm->stack.count--; 113 ucv_put(vm->stack.entries[vm->stack.count]); 114 vm->stack.entries[vm->stack.count] = NULL; 115 } 116 } 117 118 static uc_value_t * 119 uc_vm_callframe_pop(uc_vm_t *vm); 120 121 static void 122 uc_vm_close_upvals(uc_vm_t *vm, size_t slot); 123 124 static void 125 uc_vm_reset_callframes(uc_vm_t *vm) 126 { 127 while (vm->callframes.count > 0) 128 ucv_put(uc_vm_callframe_pop(vm)); 129 } 130 131 static uc_value_t * 132 uc_vm_alloc_global_scope(uc_vm_t *vm) 133 { 134 uc_value_t *scope, *arr; 135 size_t i; 136 137 scope = ucv_object_new(vm); 138 139 /* build default require() search path */ 140 arr = ucv_array_new(vm); 141 142 for (i = 0; i < vm->config->module_search_path.count; i++) 143 ucv_array_push(arr, ucv_string_new(vm->config->module_search_path.entries[i])); 144 145 /* register module related constants */ 146 ucv_object_add(scope, "REQUIRE_SEARCH_PATH", arr); 147 ucv_object_add(scope, "modules", ucv_object_new(vm)); 148 149 /* register scope math constants */ 150 ucv_object_add(scope, "NaN", ucv_double_new(NAN)); 151 ucv_object_add(scope, "Infinity", ucv_double_new(INFINITY)); 152 153 /* register global property */ 154 ucv_object_add(scope, "global", ucv_get(scope)); 155 156 uc_vm_scope_set(vm, scope); 157 158 return scope; 159 } 160 161 static void 162 uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex); 163 164 static void 165 uc_vm_signal_handler(int sig) 166 { 167 uc_vm_t *vm = uc_thread_context_get()->signal_handler_vm; 168 169 assert(vm); 170 171 uc_vm_signal_raise(vm, sig); 172 } 173 174 /* Actually wire up the self-pipe/handler array/sigaction template needed 175 * for ucode-level signal() callbacks to work, independent of whether the 176 * embedding host opted into this via config->setup_signal_handlers. Safe 177 * to call more than once (a no-op once already set up for this thread). */ 178 void 179 uc_vm_signal_handlers_ensure(uc_vm_t *vm) 180 { 181 uc_thread_context_t *tctx = uc_thread_context_get(); 182 183 if (tctx->signal_handler_vm) 184 return; 185 186 if (pipe2(vm->signal.sigpipe, O_CLOEXEC | O_NONBLOCK) != 0) 187 return; 188 189 vm->signal.handler = ucv_array_new_length(vm, UC_SYSTEM_SIGNAL_COUNT); 190 191 vm->signal.sa.sa_handler = uc_vm_signal_handler; 192 vm->signal.sa.sa_flags = SA_RESTART | SA_ONSTACK; 193 sigemptyset(&vm->signal.sa.sa_mask); 194 195 tctx->signal_handler_vm = vm; 196 } 197 198 static void 199 uc_vm_signal_handlers_setup(uc_vm_t *vm) 200 { 201 memset(&vm->signal, 0, sizeof(vm->signal)); 202 203 vm->signal.sigpipe[0] = -1; 204 vm->signal.sigpipe[1] = -1; 205 206 if (!vm->config->setup_signal_handlers) 207 return; 208 209 uc_vm_signal_handlers_ensure(vm); 210 } 211 212 static void 213 uc_vm_signal_handlers_reset(uc_vm_t *vm) 214 { 215 uc_thread_context_t *tctx = uc_thread_context_get(); 216 struct sigaction sa = { 0 }; 217 size_t i, signo; 218 219 if (vm != tctx->signal_handler_vm) 220 return; 221 222 sa.sa_handler = SIG_DFL; 223 sigemptyset(&sa.sa_mask); 224 225 for (signo = 0; signo < ucv_array_length(vm->signal.handler); signo++) 226 if (ucv_is_callable(ucv_array_get(vm->signal.handler, signo))) 227 sigaction(signo, &sa, NULL); 228 229 for (i = 0; i < ARRAY_SIZE(vm->signal.sigpipe); i++) { 230 if (vm->signal.sigpipe[i] > STDERR_FILENO) 231 close(vm->signal.sigpipe[i]); 232 233 vm->signal.sigpipe[i] = -1; 234 } 235 236 tctx->signal_handler_vm = NULL; 237 } 238 239 void uc_vm_break_init(uc_vm_t *vm) 240 { 241 vm->break_requested = false; 242 vm->break_notifyfd[0] = -1; 243 vm->break_notifyfd[1] = -1; 244 245 if (pipe2(vm->break_notifyfd, O_CLOEXEC | O_NONBLOCK) == 0) { 246 /* pipe created successfully */ 247 } 248 } 249 250 void uc_vm_break_cleanup(uc_vm_t *vm) 251 { 252 for (size_t i = 0; i < ARRAY_SIZE(vm->break_notifyfd); i++) { 253 if (vm->break_notifyfd[i] > STDERR_FILENO) 254 close(vm->break_notifyfd[i]); 255 vm->break_notifyfd[i] = -1; 256 } 257 } 258 259 void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config) 260 { 261 vm->exception.type = EXCEPTION_NONE; 262 vm->exception.message = NULL; 263 264 vm->config = config ? config : &uc_default_parse_config; 265 266 vm->open_upvals = NULL; 267 268 vm->sources = lh_kchar_table_new(16, NULL); 269 270 vm->values.prev = &vm->values; 271 vm->values.next = &vm->values; 272 273 vm->strbuf = NULL; 274 275 vm->output = stdout; 276 277 uc_vm_reset_stack(vm); 278 279 uc_vm_alloc_global_scope(vm); 280 281 uc_vm_exception_handler_set(vm, uc_vm_output_exception); 282 283 uc_vm_trace_set(vm, 0); 284 285 uc_vm_signal_handlers_setup(vm); 286 287 uc_vm_break_init(vm); 288 289 uc_thread_context_get()->refcount++; 290 } 291 292 void uc_vm_free(uc_vm_t *vm) 293 { 294 uc_thread_context_t *ctx; 295 uc_upvalref_t *ref; 296 size_t i; 297 298 uc_vm_signal_handlers_reset(vm); 299 300 uc_vm_break_cleanup(vm); 301 302 ucv_put(vm->exception.stacktrace); 303 free(vm->exception.message); 304 305 while (vm->open_upvals) { 306 ref = vm->open_upvals->next; 307 ucv_put(&vm->open_upvals->header); 308 vm->open_upvals = ref; 309 } 310 311 /* Resource type prototypes are part of the VM value pool, so release the 312 * restype refs before the final GC; any references still held by 313 * GC-managed values are dropped by ucv_freeall() itself. */ 314 for (i = 0; i < vm->restypes.count; i++) 315 ucv_put(vm->restypes.entries[i]->proto); 316 317 uc_vm_reset_callframes(vm); 318 uc_vm_reset_stack(vm); 319 uc_vector_clear(&vm->stack); 320 uc_vector_clear(&vm->callframes); 321 322 printbuf_free(vm->strbuf); 323 324 ucv_freeall(vm); 325 326 /* Release source cache entries after freeall so that all program refs 327 * to sources are already gone and the cache refs are the last ones. */ 328 if (vm->sources) { 329 struct lh_entry *entry, *next; 330 331 entry = vm->sources->head; 332 333 while (entry) { 334 next = entry->next; 335 ucv_put((uc_value_t *)lh_entry_v(entry)); 336 free((char *)lh_entry_k(entry)); 337 entry = next; 338 } 339 340 lh_table_free(vm->sources); 341 } 342 343 for (i = 0; i < vm->restypes.count; i++) 344 free(vm->restypes.entries[i]); 345 346 uc_vector_clear(&vm->restypes); 347 348 for (i = 0; i < vm->breakpoints.count; i++) 349 free(vm->breakpoints.entries[i]); 350 351 uc_vector_clear(&vm->breakpoints); 352 353 ctx = uc_thread_context_get(); 354 355 assert(ctx->refcount > 0); 356 357 if (--ctx->refcount == 0) 358 uc_thread_context_free(); 359 } 360 361 static uc_chunk_t * 362 uc_vm_frame_chunk(uc_callframe_t *frame) 363 { 364 return frame->closure ? &frame->closure->function->chunk : NULL; 365 } 366 367 static uc_program_t * 368 uc_vm_frame_program(uc_callframe_t *frame) 369 { 370 return frame->closure ? frame->closure->function->program : NULL; 371 } 372 373 static uc_source_t * 374 uc_vm_frame_source(uc_callframe_t *frame) 375 { 376 return frame->closure ? uc_program_function_source(frame->closure->function) : NULL; 377 } 378 379 static uc_callframe_t * 380 uc_vm_current_frame(uc_vm_t *vm) 381 { 382 return uc_vector_last(&vm->callframes); 383 } 384 385 static uc_program_t * 386 uc_vm_current_program(uc_vm_t *vm) 387 { 388 return uc_vm_frame_program(uc_vm_current_frame(vm)); 389 } 390 391 static uc_vm_insn_t 392 uc_vm_decode_insn(uc_vm_t *vm, uc_callframe_t *frame, uc_chunk_t *chunk) 393 { 394 uc_vm_insn_t insn; 395 int8_t argtype; 396 397 #ifndef NDEBUG 398 uint8_t *end = chunk->entries + chunk->count; 399 #endif 400 401 assert(frame->ip < end); 402 403 for (size_t i = 0; i < vm->breakpoints.count; i++) { 404 uc_breakpoint_t *bk = vm->breakpoints.entries[i]; 405 406 if (bk != NULL && (bk->ip == NULL || bk->ip == frame->ip)) 407 bk->cb(vm, bk); 408 } 409 410 insn = frame->ip[0]; 411 frame->ip++; 412 413 argtype = uc_vm_insn_to_argtype(insn); 414 415 assert(frame->ip + abs(argtype) <= end); 416 417 switch (argtype) { 418 case 0: 419 break; 420 421 case -4: 422 vm->arg.s32 = ( 423 frame->ip[0] * 0x1000000UL + 424 frame->ip[1] * 0x10000UL + 425 frame->ip[2] * 0x100UL + 426 frame->ip[3] 427 ) - 0x7fffffff; 428 frame->ip += 4; 429 break; 430 431 case 1: 432 vm->arg.u8 = frame->ip[0]; 433 frame->ip++; 434 break; 435 436 case 2: 437 vm->arg.u16 = ( 438 frame->ip[0] * 0x100 + 439 frame->ip[1] 440 ); 441 frame->ip += 2; 442 break; 443 444 case 4: 445 vm->arg.u32 = ( 446 frame->ip[0] * 0x1000000UL + 447 frame->ip[1] * 0x10000UL + 448 frame->ip[2] * 0x100UL + 449 frame->ip[3] 450 ); 451 frame->ip += 4; 452 break; 453 454 default: 455 fprintf(stderr, "Unhandled operand format: %" PRId8 "\n", argtype); 456 abort(); 457 } 458 459 return insn; 460 } 461 462 463 static char * 464 uc_vm_format_val(uc_vm_t *vm, uc_value_t *val) 465 { 466 if (!vm->strbuf) 467 vm->strbuf = xprintbuf_new(); 468 else 469 printbuf_reset(vm->strbuf); 470 471 ucv_to_stringbuf(NULL, vm->strbuf, val, true); 472 473 if (printbuf_length(vm->strbuf) >= 64) { 474 printbuf_memset(vm->strbuf, 60, '.', 3); 475 printbuf_memset(vm->strbuf, 63, 0, 1); 476 } 477 478 return vm->strbuf->buf; 479 } 480 481 static void 482 uc_vm_frame_dump(uc_vm_t *vm, uc_callframe_t *frame) 483 { 484 uc_chunk_t *chunk = uc_vm_frame_chunk(frame); 485 uc_function_t *function; 486 uc_closure_t *closure; 487 uc_upvalref_t *ref; 488 uc_value_t *v; 489 size_t i; 490 491 fprintf(stderr, " [*] CALLFRAME[%zx]\n", 492 frame - vm->callframes.entries); 493 494 fprintf(stderr, " |- stackframe %zu/%zu\n", 495 frame->stackframe, vm->stack.count); 496 497 fprintf(stderr, " |- ctx %s\n", 498 uc_vm_format_val(vm, frame->ctx)); 499 500 if (frame->tco) 501 fprintf(stderr, " |- tailcall (%u callframes omitted)\n", 502 frame->tco); 503 504 if (chunk) { 505 closure = frame->closure; 506 function = closure->function; 507 508 fprintf(stderr, " `- %zu upvalues\n", 509 function->nupvals); 510 511 for (i = 0; i < function->nupvals; i++) { 512 ref = closure->upvals[i]; 513 v = uc_chunk_debug_get_variable(chunk, 0, i, true); 514 515 fprintf(stderr, " [%zu] <%p> %s ", 516 i, (void *)ref, uc_vm_format_val(vm, v)); 517 518 if (!ref) { 519 fprintf(stderr, "{unresolved}\n"); 520 } 521 else if (ref->closed) { 522 fprintf(stderr, "{closed} %s\n", 523 uc_vm_format_val(vm, ref->value)); 524 } 525 else { 526 fprintf(stderr, "{open[%zu]} %s\n", 527 ref->slot, 528 uc_vm_format_val(vm, vm->stack.entries[ref->slot])); 529 } 530 531 ucv_put(v); 532 } 533 } 534 } 535 536 static uc_value_t * 537 uc_vm_resolve_upval(uc_vm_t *vm, uc_value_t *value) 538 { 539 uc_upvalref_t *ref; 540 uc_value_t *rv; 541 542 #ifdef __clang_analyzer__ 543 /* Clang static analyzer does not understand that ucv_type(NULL) can't 544 * possibly yield UC_UPVALUE. Nudge it. */ 545 if (value != NULL && ucv_type(value) == UC_UPVALUE) 546 #else 547 if (ucv_type(value) == UC_UPVALUE) 548 #endif 549 { 550 ref = ucv_as_upvalue(value); 551 552 if (ref->closed) 553 rv = ucv_get(ref->value); 554 else 555 rv = ucv_get(vm->stack.entries[ref->slot]); 556 557 ucv_put(value); 558 559 return rv; 560 } 561 562 return value; 563 } 564 565 void 566 uc_vm_stack_push(uc_vm_t *vm, uc_value_t *value) 567 { 568 uc_vector_push(&vm->stack, uc_vm_resolve_upval(vm, value)); 569 570 if (vm->trace) { 571 fprintf(stderr, " [+%zd] %s\n", 572 vm->stack.count - 1, 573 uc_vm_format_val(vm, vm->stack.entries[vm->stack.count - 1])); 574 } 575 } 576 577 uc_value_t * 578 uc_vm_stack_pop(uc_vm_t *vm) 579 { 580 uc_value_t *rv; 581 582 vm->stack.count--; 583 rv = vm->stack.entries[vm->stack.count]; 584 vm->stack.entries[vm->stack.count] = NULL; 585 586 if (vm->trace) { 587 fprintf(stderr, " [-%zd] %s\n", 588 vm->stack.count, 589 uc_vm_format_val(vm, rv)); 590 } 591 592 return rv; 593 } 594 595 uc_value_t * 596 uc_vm_stack_peek(uc_vm_t *vm, size_t offset) 597 { 598 return vm->stack.entries[vm->stack.count + (-1 - offset)]; 599 } 600 601 static void 602 uc_vm_stack_set(uc_vm_t *vm, size_t offset, uc_value_t *value) 603 { 604 if (vm->trace) { 605 fprintf(stderr, " [!%zu] %s\n", 606 offset, 607 uc_vm_format_val(vm, value)); 608 } 609 610 ucv_put(vm->stack.entries[offset]); 611 vm->stack.entries[offset] = value; 612 } 613 614 static void 615 uc_vm_call_native(uc_vm_t *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs) 616 { 617 uc_value_t *res = NULL; 618 uc_callframe_t *frame; 619 620 /* add new callframe */ 621 frame = uc_vector_push(&vm->callframes, { 622 .stackframe = vm->stack.count - nargs - 1, 623 .cfunction = fptr, 624 .closure = NULL, 625 .ctx = ctx, 626 .mcall = mcall 627 }); 628 629 if (vm->trace) 630 uc_vm_frame_dump(vm, frame); 631 632 res = fptr->cfn(vm, nargs); 633 634 /* Reset stack, check for callframe depth since an uncatched exception in managed 635 * code executed by fptr->cfn() could've reset the callframe stack already. */ 636 if (vm->callframes.count > 0) 637 ucv_put(uc_vm_callframe_pop(vm)); 638 639 /* push return value */ 640 if (!vm->exception.type) 641 uc_vm_stack_push(vm, res); 642 else 643 ucv_put(res); 644 } 645 646 /* Replaces the current call frame by an invocation frame for the given closure, 647 * reusing the stack slots formerly occupied by the current frame. 648 * 649 * Since neither the call frame vector nor the value stack grow when invoking the 650 * callee, this allows unbounded tail recursion. 651 * 652 * On entry, the stack holds the invoked function value and its arguments at the 653 * top, optionally preceded by the receiver value of a method invocation. */ 654 static void 655 uc_vm_frame_reinit(uc_vm_t *vm, uc_closure_t *closure, uc_value_t *ctx, 656 bool mcall, size_t nargs) 657 { 658 size_t i, blocksrc, blockdst, blocklen, blockofs; 659 uc_callframe_t *frame = uc_vm_current_frame(vm); 660 uc_value_t *oldclosure, *oldctx, *val; 661 662 /* the slot the invoking code expects the eventual return value at, which is 663 * the slot of the current frame's function value, or - for method calls - of 664 * the receiver value immediately below it */ 665 blockdst = frame->stackframe - (frame->mcall ? 1 : 0); 666 667 /* number of stack slots occupied by the receiver, function and arguments */ 668 blocklen = nargs + 1 + (mcall ? 1 : 0); 669 670 /* slot of the invoked function value, or of the receiver value preceding it */ 671 blocksrc = vm->stack.count - blocklen; 672 673 /* the value block is relocated towards the start of the stack, so the slots 674 * it occupies are always read before being overwritten */ 675 blockofs = blocksrc - blockdst; 676 677 /* close upvalues referring to the current frame's stack slots before overwriting them */ 678 uc_vm_close_upvals(vm, frame->stackframe); 679 680 /* remember the value references owned by the current frame */ 681 oldclosure = frame->closure ? &frame->closure->header : NULL; 682 oldctx = frame->ctx; 683 684 /* move receiver, function value and arguments down into the slots of the frame 685 * being replaced, releasing the local variable, temporary and receiver values 686 * formerly held by them and clearing stale slots left above the new frame */ 687 for (i = blockdst; i < vm->stack.count; i++) { 688 val = (i - blockdst < blocklen) ? vm->stack.entries[i + blockofs] : NULL; 689 690 /* the slot holds a value owned by the current frame unless it is part of 691 * the value block being relocated */ 692 if (i < blocksrc) 693 ucv_put(vm->stack.entries[i]); 694 695 vm->stack.entries[i] = val; 696 } 697 698 vm->stack.count = blockdst + blocklen; 699 700 /* reinitialize the call frame in place; the receiver value of a method call 701 * occupies the slot below the invoked function value. the tco counter records 702 * that this frame replaced the tail calling one, so stack traces can indicate 703 * the collapsed frames */ 704 frame->stackframe = blockdst + (mcall ? 1 : 0); 705 frame->cfunction = NULL; 706 frame->closure = closure; 707 frame->ctx = ctx; 708 frame->ip = closure->function->chunk.entries; 709 frame->mcall = mcall; 710 frame->strict = closure->function->strict; 711 712 /* saturate rather than wrap, so the count stays a valid (if capped) number 713 * of omitted frames */ 714 if (frame->tco < 0xffff) 715 frame->tco++; 716 717 if (vm->trace) 718 uc_vm_frame_dump(vm, frame); 719 720 /* release the references formerly owned by the current frame */ 721 ucv_put(oldclosure); 722 ucv_put(oldctx); 723 } 724 725 static bool 726 uc_vm_call_function(uc_vm_t *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, 727 size_t argspec, bool tail) 728 { 729 size_t i, j, stackoff, nargs = argspec & 0xffff; 730 size_t nspreads = (argspec >> 16) & 0x7fff; 731 uc_callframe_t *frame = NULL; 732 uc_value_t *ellip, *arg; 733 uc_function_t *function; 734 uc_closure_t *closure; 735 uint16_t slot, tmp; 736 char *s; 737 738 /* a tail invocation reuses the current frame, so it never grows the stack */ 739 if (!tail && vm->callframes.count >= 1000) { 740 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Too much recursion"); 741 ucv_put(ctx); 742 ucv_put(fno); 743 744 return false; 745 } 746 747 stackoff = vm->stack.count - nargs - 1; 748 749 /* argument list contains spread operations, we need to reshuffle the stack */ 750 if (nspreads > 0) { 751 frame = uc_vm_current_frame(vm); 752 753 /* create temporary array */ 754 ellip = ucv_array_new_length(vm, nargs); 755 756 /* pop original stack values and push to temp array in reverse order */ 757 for (i = 0; i < nargs; i++) 758 ucv_array_push(ellip, uc_vm_stack_pop(vm)); 759 760 /* for each spread value index ... */ 761 for (i = 0, slot = nargs; i < nspreads; i++) { 762 /* decode stack depth value */ 763 tmp = frame->ip[0] * 0x100 + frame->ip[1]; 764 frame->ip += 2; 765 766 /* push each preceeding non-spread value to the stack */ 767 for (j = slot; j > tmp + 1UL; j--) 768 uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, j - 1))); 769 770 /* read spread value at index... */ 771 slot = tmp; 772 arg = ucv_get(ucv_array_get(ellip, slot)); 773 774 /* ... ensure that it is an array type ... */ 775 if (ucv_type(arg) != UC_ARRAY) { 776 s = ucv_to_string(vm, arg); 777 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); 778 free(s); 779 ucv_put(ctx); 780 ucv_put(fno); 781 ucv_put(ellip); 782 783 return false; 784 } 785 786 /* ... and push each spread array value as argument to the stack */ 787 for (j = 0; j < ucv_array_length(arg); j++) 788 uc_vm_stack_push(vm, ucv_get(ucv_array_get(arg, j))); 789 790 ucv_put(arg); 791 } 792 793 /* push remaining non-spread arguments to the stack */ 794 for (i = slot; i > 0; i--) 795 uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, i - 1))); 796 797 /* free temp array */ 798 ucv_put(ellip); 799 800 /* update arg count */ 801 nargs = vm->stack.count - stackoff - 1; 802 } 803 804 /* __call__ dispatch: if fno is not itself callable (not a closure or 805 * cfunction) but carries a __call__ metamethod somewhere in its prototype 806 * chain, invoke that method with the instance as `this`. The instance 807 * becomes the new ctx; the original ctx (if any) is discarded. The tail 808 * flag is preserved so `return foo()` still TCOs through the dispatch. */ 809 if (ucv_type(fno) != UC_CFUNCTION && ucv_type(fno) != UC_CLOSURE) { 810 uc_value_t *meta = ucv_metamethod_lookup(fno, "__call__"); 811 812 if (ucv_is_callable(meta)) { 813 ucv_put(ctx); 814 815 /* the instance becomes `this` and is invoked in place of the 816 * __call__ method, so hand the reference to ctx over */ 817 ctx = fno; 818 fno = ucv_get(meta); 819 } 820 } 821 822 /* is a native function; such functions are always invoked in a fresh frame, 823 * even when requested as tail call, since the foreign code may rely on the 824 * stack layout of an ordinary invocation */ 825 if (ucv_type(fno) == UC_CFUNCTION) { 826 uc_vm_call_native(vm, ctx, ucv_as_cfunction(fno), mcall, nargs); 827 828 return true; 829 } 830 831 if (ucv_type(fno) != UC_CLOSURE) { 832 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "left-hand side is not a function"); 833 ucv_put(ctx); 834 ucv_put(fno); 835 836 return false; 837 } 838 839 closure = ucv_as_closure(fno); 840 function = closure->function; 841 842 /* fewer arguments on stack than function expects => pad */ 843 if (nargs < function->nargs) { 844 for (i = nargs; i < function->nargs; i++) { 845 if (function->vararg && (i + 1) == function->nargs) 846 uc_vm_stack_push(vm, ucv_array_new_length(vm, 0)); 847 else 848 uc_vm_stack_push(vm, NULL); 849 } 850 } 851 852 /* more arguments on stack than function expects... */ 853 else if (nargs > function->nargs - function->vararg) { 854 /* is a vararg function => pass excess args as array */ 855 if (function->vararg) { 856 ellip = ucv_array_new_length(vm, nargs - (function->nargs - 1)); 857 858 for (i = function->nargs; i <= nargs; i++) 859 ucv_array_push(ellip, uc_vm_stack_peek(vm, nargs - i)); 860 861 for (i = function->nargs; i <= nargs; i++) 862 uc_vm_stack_pop(vm); 863 864 uc_vm_stack_push(vm, ellip); 865 } 866 867 /* static amount of args => drop excess values */ 868 else { 869 for (i = function->nargs; i < nargs; i++) 870 ucv_put(uc_vm_stack_pop(vm)); 871 } 872 } 873 874 /* tail call: reuse the current call frame instead of pushing a new one. The 875 * number of values above the invoked function may differ from the encoded 876 * argument count due to spread operations or excess argument handling */ 877 if (tail) { 878 uc_vm_frame_reinit(vm, closure, ctx, mcall, vm->stack.count - stackoff - 1); 879 880 return true; 881 } 882 883 frame = uc_vector_push(&vm->callframes, { 884 .stackframe = stackoff, 885 .cfunction = NULL, 886 .closure = closure, 887 .ctx = ctx, 888 .ip = function->chunk.entries, 889 .mcall = mcall, 890 .strict = function->strict 891 }); 892 893 if (vm->trace) 894 uc_vm_frame_dump(vm, frame); 895 896 return true; 897 } 898 899 static uc_source_t *last_source = NULL; 900 static size_t last_srcpos = 0; 901 902 static void 903 uc_dump_insn(uc_vm_t *vm, uint8_t *pos, uc_vm_insn_t insn) 904 { 905 uc_callframe_t *frame = uc_vm_current_frame(vm); 906 uc_chunk_t *chunk = uc_vm_frame_chunk(frame); 907 uc_stringbuf_t *buf = NULL; 908 uc_value_t *cnst = NULL; 909 uc_source_t *source; 910 int8_t argtype; 911 size_t srcpos; 912 913 srcpos = uc_program_function_srcpos(frame->closure->function, pos - chunk->entries); 914 source = uc_vm_frame_source(frame); 915 916 if (last_srcpos == 0 || last_source != source || srcpos != last_srcpos) { 917 buf = xprintbuf_new(); 918 919 uc_source_context_format(buf, source, srcpos, true); 920 fwrite(buf->buf, 1, printbuf_length(buf), stderr); 921 printbuf_free(buf); 922 923 last_source = source; 924 last_srcpos = srcpos; 925 } 926 927 fprintf(stderr, "%08zx %s", pos - chunk->entries, 928 uc_vm_insn_to_name(insn)); 929 930 argtype = uc_vm_insn_to_argtype(insn); 931 932 switch (argtype) { 933 case 0: 934 break; 935 936 case -1: 937 fprintf(stderr, " {%s%hhd}", vm->arg.s8 < 0 ? "" : "+", vm->arg.s8); 938 break; 939 940 case -2: 941 fprintf(stderr, " {%c0x%hx}", 942 vm->arg.s16 < 0 ? '-' : '+', 943 (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16)); 944 break; 945 946 case -4: 947 fprintf(stderr, " {%c0x%x}", 948 vm->arg.s32 < 0 ? '-' : '+', 949 (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32)); 950 break; 951 952 case 1: 953 fprintf(stderr, " {%hhu}", vm->arg.u8); 954 break; 955 956 case 2: 957 fprintf(stderr, " {0x%hx}", vm->arg.u16); 958 break; 959 960 case 4: 961 fprintf(stderr, " {0x%x}", vm->arg.u32); 962 break; 963 964 default: 965 fprintf(stderr, " (unknown operand format: %" PRId8 ")", argtype); 966 break; 967 } 968 969 switch (insn) { 970 case I_LOAD: 971 case I_LVAR: 972 case I_SVAR: 973 cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32); 974 975 fprintf(stderr, "\t; %s", 976 cnst ? uc_vm_format_val(vm, cnst) : "(?)"); 977 978 ucv_put(cnst); 979 break; 980 981 case I_LLOC: 982 case I_LUPV: 983 case I_SLOC: 984 case I_SUPV: 985 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32, (insn == I_LUPV || insn == I_SUPV)); 986 987 fprintf(stderr, "\t; %s", 988 cnst ? uc_vm_format_val(vm, cnst) : "(?)"); 989 990 ucv_put(cnst); 991 break; 992 993 case I_ULOC: 994 case I_UUPV: 995 cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32 & 0x00ffffff, (insn == I_UUPV)); 996 /* fall through */ 997 998 case I_UVAR: 999 if (!cnst) 1000 cnst = uc_program_get_constant(uc_vm_frame_program(uc_vector_last(&vm->callframes)), vm->arg.u32 & 0x00ffffff); 1001 1002 fprintf(stderr, "\t; %s (%s)", 1003 cnst ? uc_vm_format_val(vm, cnst) : "(?)", 1004 uc_vm_insn_to_name(vm->arg.u32 >> 24)); 1005 1006 ucv_put(cnst); 1007 break; 1008 1009 case I_UVAL: 1010 fprintf(stderr, "\t; (%s)", uc_vm_insn_to_name(vm->arg.u8)); 1011 break; 1012 1013 default: 1014 break; 1015 } 1016 1017 fprintf(stderr, "\n"); 1018 } 1019 1020 static uc_value_t * 1021 uc_vm_exception_tostring(uc_vm_t *vm, size_t nargs) 1022 { 1023 uc_callframe_t *frame = uc_vm_current_frame(vm); 1024 uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL); 1025 1026 return message ? ucv_get(message) : ucv_string_new("Exception"); 1027 } 1028 1029 uc_value_t * 1030 uc_vm_exception_object(uc_vm_t *vm) 1031 { 1032 uc_exception_type_t type = vm->exception.type; 1033 const char *message = vm->exception.message; 1034 uc_value_t *stacktrace = vm->exception.stacktrace; 1035 uc_value_t *exception_prototype = uc_vm_registry_get(vm, "vm.exception.proto"); 1036 uc_value_t *exo; 1037 1038 if (exception_prototype == NULL) { 1039 exception_prototype = ucv_object_new(vm); 1040 1041 ucv_object_add(exception_prototype, "tostring", 1042 ucv_cfunction_new("tostring", uc_vm_exception_tostring)); 1043 1044 uc_vm_registry_set(vm, "vm.exception.proto", exception_prototype); 1045 } 1046 1047 exo = ucv_object_new(vm); 1048 1049 ucv_object_add(exo, "type", ucv_string_new(exception_type_strings[type])); 1050 ucv_object_add(exo, "message", ucv_string_new(message)); 1051 ucv_object_add(exo, "stacktrace", ucv_get(stacktrace)); 1052 1053 ucv_prototype_set(exo, ucv_get(exception_prototype)); 1054 1055 return exo; 1056 } 1057 1058 static void 1059 uc_vm_clear_exception(uc_vm_t *vm) 1060 { 1061 vm->exception.type = EXCEPTION_NONE; 1062 1063 ucv_put(vm->exception.stacktrace); 1064 vm->exception.stacktrace = NULL; 1065 1066 free(vm->exception.message); 1067 vm->exception.message = NULL; 1068 } 1069 1070 /* Well-known sentinel `uc_breakpoint_t.ip` value identifying the dedicated 1071 * "break on uncaught exception" system breakpoint (see debug.c's BK_UNCAUGHT). 1072 * It deliberately isn't a real bytecode address, so the ordinary 1073 * ip-matching breakpoint dispatch in uc_vm_decode_insn() - which walks 1074 * vm->breakpoints on every single instruction - never fires it by 1075 * accident; it is only ever invoked explicitly, from the exception label in 1076 * uc_vm_execute_chunk() below, at the one moment it actually applies. */ 1077 static uint8_t uc_breakpoint_uncaught_exception_storage; 1078 uint8_t *const UC_BREAKPOINT_UNCAUGHT_EXCEPTION = 1079 &uc_breakpoint_uncaught_exception_storage; 1080 1081 /* Non-destructively predict whether uc_vm_handle_exception()'s real unwind 1082 * loop (below) would find a handler for the currently raised exception 1083 * anywhere between the current callframe and `caller` (the frame depth this 1084 * uc_vm_execute_chunk() invocation was entered at - the same boundary its 1085 * own unwind loop stops at). Mirrors that loop's exact stopping conditions 1086 * (a native callframe, or reaching `caller`) but only inspects state; nops 1087 * of the stack/exception state, jumping ip. Used to decide whether to break 1088 * into the debugger *before* unwinding starts, while the original throwing 1089 * frame - locals, exact position - is still fully intact, since once 1090 * uc_vm_handle_exception() starts really popping frames that's gone. */ 1091 static bool 1092 uc_vm_exception_would_be_caught(uc_vm_t *vm, size_t caller) 1093 { 1094 for (size_t i = vm->callframes.count; i > caller; i--) { 1095 uc_callframe_t *frame = &vm->callframes.entries[i - 1]; 1096 1097 if (!frame->closure) 1098 return false; 1099 1100 uc_chunk_t *chunk = &frame->closure->function->chunk; 1101 size_t pos = frame->ip - chunk->entries; 1102 1103 for (size_t j = 0; j < chunk->ehranges.count; j++) { 1104 if (pos >= chunk->ehranges.entries[j].from && 1105 pos < chunk->ehranges.entries[j].to) 1106 return true; 1107 } 1108 } 1109 1110 return false; 1111 } 1112 1113 static bool 1114 uc_vm_handle_exception(uc_vm_t *vm) 1115 { 1116 uc_callframe_t *frame = NULL; 1117 uc_chunk_t *chunk = NULL; 1118 uc_value_t *exo; 1119 size_t i, pos; 1120 1121 if (vm->callframes.count) 1122 frame = uc_vm_current_frame(vm); 1123 1124 if (!frame || !frame->closure) 1125 return false; 1126 1127 chunk = uc_vm_frame_chunk(frame); 1128 pos = frame->ip - chunk->entries; 1129 1130 /* iterate the known exception ranges, see if the current ip falls into any of them */ 1131 for (i = 0; i < chunk->ehranges.count; i++) { 1132 /* skip nonmatching ranges */ 1133 if (pos < chunk->ehranges.entries[i].from || 1134 pos >= chunk->ehranges.entries[i].to) 1135 continue; 1136 1137 /* we found a matching range... first unwind stack */ 1138 while (vm->stack.count > frame->stackframe + chunk->ehranges.entries[i].slot) 1139 ucv_put(uc_vm_stack_pop(vm)); 1140 1141 /* prepare exception object and expose it to user handler code */ 1142 exo = uc_vm_exception_object(vm); 1143 1144 uc_vm_stack_push(vm, exo); 1145 1146 /* reset exception information */ 1147 uc_vm_clear_exception(vm); 1148 1149 /* jump to exception handler */ 1150 if (chunk->ehranges.entries[i].target >= chunk->count) { 1151 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range"); 1152 return false; 1153 } 1154 1155 #if 0 1156 if (vm->trace && chunk->entries + chunk->ehranges.entries[i].target > frame->ip) { 1157 while (frame->ip < chunk->entries + chunk->ehranges.entries[i].target) { 1158 fprintf(stderr, "(eh:skip) [%p:%zu] ", chunk, frame->ip - chunk->entries); 1159 uc_dump_insn(vm, frame->ip, uc_vm_decode_insn(vm, frame, chunk)); 1160 } 1161 } 1162 #endif 1163 1164 frame->ip = chunk->entries + chunk->ehranges.entries[i].target; 1165 1166 return true; 1167 } 1168 1169 return false; 1170 } 1171 1172 static uc_value_t * 1173 uc_vm_capture_stacktrace(uc_vm_t *vm, size_t i) 1174 { 1175 uc_value_t *stacktrace, *entry, *last = NULL; 1176 uc_function_t *function; 1177 uc_callframe_t *frame; 1178 uc_source_t *source; 1179 size_t off, srcpos; 1180 char *name; 1181 1182 stacktrace = ucv_array_new(vm); 1183 1184 for (; i > 0; i--) { 1185 frame = &vm->callframes.entries[i - 1]; 1186 entry = ucv_object_new(vm); 1187 1188 if (frame->closure) { 1189 function = frame->closure->function; 1190 source = uc_program_function_source(function); 1191 1192 off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1; 1193 srcpos = uc_program_function_srcpos(function, off); 1194 1195 ucv_object_add(entry, "filename", ucv_string_new(source->filename)); 1196 ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(source, &srcpos))); 1197 ucv_object_add(entry, "byte", ucv_int64_new(srcpos)); 1198 } 1199 1200 if (i > 1) { 1201 if (frame->closure) { 1202 if (frame->closure->function->name[0]) 1203 name = frame->closure->function->name; 1204 else if (frame->closure->is_arrow) 1205 name = "[arrow function]"; 1206 else 1207 name = "[anonymous function]"; 1208 } 1209 else { 1210 name = frame->cfunction->name; 1211 } 1212 1213 ucv_object_add(entry, "function", ucv_string_new(name)); 1214 } 1215 1216 /* record the number of call frames collapsed into this one by tail call 1217 * optimization, so consumers can indicate the missing frames */ 1218 if (frame->tco) 1219 ucv_object_add(entry, "tco", ucv_int64_new(frame->tco)); 1220 1221 if (!ucv_is_equal(last, entry)) { 1222 ucv_array_push(stacktrace, entry); 1223 last = entry; 1224 } 1225 else { 1226 ucv_put(entry); 1227 } 1228 } 1229 1230 return stacktrace; 1231 } 1232 1233 static uc_value_t * 1234 uc_vm_get_error_context(uc_vm_t *vm) 1235 { 1236 size_t offset, i, byte, line; 1237 uc_value_t *stacktrace; 1238 uc_callframe_t *frame; 1239 uc_stringbuf_t *buf; 1240 uc_chunk_t *chunk; 1241 1242 if (vm->callframes.count == 0) 1243 return NULL; 1244 1245 /* skip to first non-native function call frame */ 1246 for (i = vm->callframes.count; i > 1; i--) 1247 if (vm->callframes.entries[i - 1].closure) 1248 break; 1249 1250 frame = &vm->callframes.entries[i - 1]; 1251 1252 if (!frame->closure) 1253 return NULL; 1254 1255 chunk = uc_vm_frame_chunk(frame); 1256 offset = uc_program_function_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1); 1257 stacktrace = uc_vm_capture_stacktrace(vm, i); 1258 1259 buf = ucv_stringbuf_new(); 1260 1261 byte = offset; 1262 line = uc_source_get_line(uc_program_function_source(frame->closure->function), &byte); 1263 1264 if (line) 1265 uc_error_context_format(buf, uc_vm_frame_source(frame), stacktrace, offset); 1266 else if (frame->ip != chunk->entries) 1267 ucv_stringbuf_printf(buf, "At instruction %zu", (frame->ip - chunk->entries) - 1); 1268 else 1269 ucv_stringbuf_append(buf, "At start of program"); 1270 1271 ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf)); 1272 1273 return stacktrace; 1274 } 1275 1276 void __attribute__((format(printf, 3, 0))) 1277 uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...) 1278 { 1279 va_list ap; 1280 1281 vm->exception.type = type; 1282 1283 free(vm->exception.message); 1284 1285 va_start(ap, fmt); 1286 xvasprintf(&vm->exception.message, fmt, ap); 1287 va_end(ap); 1288 1289 ucv_put(vm->exception.stacktrace); 1290 vm->exception.stacktrace = uc_vm_get_error_context(vm); 1291 } 1292 1293 static bool 1294 uc_vm_test_strict_equality(uc_value_t *v1, uc_value_t *v2, bool nan_equal) 1295 { 1296 uc_type_t t1 = ucv_type(v1); 1297 uc_type_t t2 = ucv_type(v2); 1298 double d1, d2; 1299 1300 if (t1 != t2) 1301 return false; 1302 1303 switch (t1) { 1304 case UC_DOUBLE: 1305 d1 = ucv_as_double(v1)->dbl; 1306 d2 = ucv_as_double(v2)->dbl; 1307 1308 if (isnan(d1) && isnan(d2)) 1309 return nan_equal; 1310 1311 return (d1 == d2); 1312 1313 case UC_NULL: 1314 case UC_BOOLEAN: 1315 case UC_INTEGER: 1316 case UC_STRING: 1317 return ucv_is_equal(v1, v2); 1318 1319 default: 1320 return (v1 == v2); 1321 } 1322 } 1323 1324 1325 static void 1326 uc_vm_insn_load(uc_vm_t *vm, uc_vm_insn_t insn) 1327 { 1328 switch (insn) { 1329 case I_LOAD: 1330 uc_vm_stack_push(vm, uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32)); 1331 break; 1332 1333 case I_LOAD8: 1334 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u8)); 1335 break; 1336 1337 case I_LOAD16: 1338 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u16)); 1339 break; 1340 1341 case I_LOAD32: 1342 uc_vm_stack_push(vm, ucv_uint64_new(vm->arg.u32)); 1343 break; 1344 1345 default: 1346 break; 1347 } 1348 } 1349 1350 static void 1351 uc_vm_insn_load_regexp(uc_vm_t *vm, uc_vm_insn_t insn) 1352 { 1353 uc_value_t *re, *jstr = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32); 1354 bool icase = false, newline = false, global = false; 1355 char *str, *err = NULL; 1356 1357 if (ucv_type(jstr) != UC_STRING || ucv_string_length(jstr) < 2) { 1358 uc_vm_stack_push(vm, NULL); 1359 ucv_put(jstr); 1360 1361 return; 1362 } 1363 1364 str = ucv_string_get(jstr); 1365 1366 global = (*str & (1 << 0)); 1367 icase = (*str & (1 << 1)); 1368 newline = (*str & (1 << 2)); 1369 1370 re = ucv_regexp_new(++str, icase, newline, global, &err); 1371 1372 ucv_put(jstr); 1373 1374 if (re) 1375 uc_vm_stack_push(vm, re); 1376 else 1377 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err); 1378 1379 free(err); 1380 } 1381 1382 static void 1383 uc_vm_insn_load_null(uc_vm_t *vm, uc_vm_insn_t insn) 1384 { 1385 uc_vm_stack_push(vm, NULL); 1386 } 1387 1388 static void 1389 uc_vm_insn_load_bool(uc_vm_t *vm, uc_vm_insn_t insn) 1390 { 1391 uc_vm_stack_push(vm, ucv_boolean_new(insn == I_LTRUE)); 1392 } 1393 1394 static void 1395 uc_vm_insn_load_var(uc_vm_t *vm, uc_vm_insn_t insn) 1396 { 1397 uc_value_t *name, *val = NULL; 1398 uc_value_t *scope, *next; 1399 bool found; 1400 1401 scope = vm->globals; 1402 name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32); 1403 1404 while (ucv_type(name) == UC_STRING) { 1405 val = ucv_object_get(scope, ucv_string_get(name), &found); 1406 1407 if (found) 1408 break; 1409 1410 next = ucv_prototype_get(scope); 1411 1412 if (!next) { 1413 if (uc_vm_is_strict(vm)) { 1414 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 1415 "access to undeclared variable %s", 1416 ucv_string_get(name)); 1417 } 1418 1419 break; 1420 } 1421 1422 scope = next; 1423 } 1424 1425 ucv_put(name); 1426 1427 uc_vm_stack_push(vm, ucv_get(val)); 1428 } 1429 1430 static void 1431 uc_vm_insn_load_val(uc_vm_t *vm, uc_vm_insn_t insn) 1432 { 1433 uc_value_t *k = uc_vm_stack_pop(vm); 1434 uc_value_t *v = uc_vm_stack_pop(vm); 1435 1436 switch (ucv_type(v)) { 1437 case UC_RESOURCE: 1438 case UC_OBJECT: 1439 case UC_ARRAY: 1440 /* aware read: dispatches __get__ on a missing key */ 1441 uc_vm_stack_push(vm, ucv_key_get(vm, v, k)); 1442 break; 1443 1444 default: 1445 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 1446 "left-hand side expression is %s", 1447 v ? "not an array or object" : "null"); 1448 1449 break; 1450 } 1451 1452 ucv_put(k); 1453 ucv_put(v); 1454 } 1455 1456 static void 1457 uc_vm_insn_peek_val(uc_vm_t *vm, uc_vm_insn_t insn) 1458 { 1459 uc_value_t *k = uc_vm_stack_pop(vm); 1460 uc_value_t *v = uc_vm_stack_peek(vm, 0); 1461 1462 switch (ucv_type(v)) { 1463 case UC_RESOURCE: 1464 case UC_OBJECT: 1465 case UC_ARRAY: 1466 /* aware read: dispatches __get__ on a missing key */ 1467 uc_vm_stack_push(vm, ucv_key_get(vm, v, k)); 1468 break; 1469 1470 default: 1471 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 1472 "left-hand side expression is %s", 1473 v ? "not an array or object" : "null"); 1474 1475 break; 1476 } 1477 1478 ucv_put(k); 1479 } 1480 1481 static void 1482 uc_vm_insn_load_upval(uc_vm_t *vm, uc_vm_insn_t insn) 1483 { 1484 uc_callframe_t *frame = uc_vm_current_frame(vm); 1485 uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; 1486 1487 if (ref->closed) 1488 uc_vm_stack_push(vm, ucv_get(ref->value)); 1489 else 1490 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[ref->slot])); 1491 } 1492 1493 static void 1494 uc_vm_insn_load_local(uc_vm_t *vm, uc_vm_insn_t insn) 1495 { 1496 uc_callframe_t *frame = uc_vm_current_frame(vm); 1497 1498 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); 1499 } 1500 1501 static uc_upvalref_t * 1502 uc_vm_capture_upval(uc_vm_t *vm, size_t slot) 1503 { 1504 uc_upvalref_t *curr = vm->open_upvals; 1505 uc_upvalref_t *prev = NULL; 1506 uc_upvalref_t *created; 1507 char *s; 1508 1509 while (curr && curr->slot > slot) { 1510 prev = curr; 1511 curr = curr->next; 1512 } 1513 1514 if (curr && curr->slot == slot) { 1515 if (vm->trace) { 1516 s = ucv_to_string(NULL, vm->stack.entries[slot]); 1517 fprintf(stderr, " {+%zu} <%p> %s\n", slot, (void *)curr, s); 1518 free(s); 1519 } 1520 1521 return curr; 1522 } 1523 1524 created = (uc_upvalref_t *)ucv_upvalref_new(slot); 1525 created->next = curr; 1526 1527 if (vm->trace) { 1528 s = ucv_to_string(NULL, vm->stack.entries[slot]); 1529 fprintf(stderr, " {*%zu} <%p> %s\n", slot, (void *)created, s); 1530 free(s); 1531 } 1532 1533 if (prev) 1534 prev->next = created; 1535 else 1536 vm->open_upvals = created; 1537 1538 return created; 1539 } 1540 1541 static void 1542 uc_vm_close_upvals(uc_vm_t *vm, size_t slot) 1543 { 1544 uc_upvalref_t *ref; 1545 1546 while (vm->open_upvals && vm->open_upvals->slot >= slot) { 1547 ref = vm->open_upvals; 1548 ref->value = ucv_get(vm->stack.entries[ref->slot]); 1549 ref->closed = true; 1550 1551 if (vm->trace) { 1552 fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, 1553 (void *)ref, 1554 uc_vm_format_val(vm, ref->value)); 1555 } 1556 1557 vm->open_upvals = ref->next; 1558 ucv_put(&ref->header); 1559 } 1560 } 1561 1562 static void 1563 uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn) 1564 { 1565 uc_callframe_t *frame = uc_vm_current_frame(vm); 1566 uc_function_t *function = uc_program_function_load(uc_vm_current_program(vm), vm->arg.u32); 1567 uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN); 1568 volatile int32_t uv; 1569 size_t i; 1570 1571 uc_vm_stack_push(vm, &closure->header); 1572 1573 if (function->module) 1574 return; 1575 1576 for (i = 0; i < function->nupvals; i++) { 1577 uv = ( 1578 frame->ip[0] * 0x1000000 + 1579 frame->ip[1] * 0x10000 + 1580 frame->ip[2] * 0x100 + 1581 frame->ip[3] 1582 ) - 0x7fffffff; 1583 1584 if (uv < 0) 1585 closure->upvals[i] = uc_vm_capture_upval(vm, frame->stackframe - (uv + 1)); 1586 else 1587 closure->upvals[i] = frame->closure->upvals[uv]; 1588 1589 ucv_get(&closure->upvals[i]->header); 1590 1591 frame->ip += 4; 1592 } 1593 } 1594 1595 static void 1596 uc_vm_insn_store_var(uc_vm_t *vm, uc_vm_insn_t insn) 1597 { 1598 uc_value_t *name, *v = uc_vm_stack_pop(vm); 1599 uc_value_t *scope, *next; 1600 bool found; 1601 1602 scope = vm->globals; 1603 name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32); 1604 1605 while (ucv_type(name) == UC_STRING) { 1606 ucv_object_get(scope, ucv_string_get(name), &found); 1607 1608 if (found) 1609 break; 1610 1611 next = ucv_prototype_get(scope); 1612 1613 if (!next) { 1614 if (uc_vm_is_strict(vm)) { 1615 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 1616 "access to undeclared variable %s", 1617 ucv_string_get(name)); 1618 ucv_put(name); 1619 ucv_put(v); 1620 1621 return; 1622 } 1623 1624 break; 1625 } 1626 1627 scope = next; 1628 } 1629 1630 if (scope && ucv_type(name) == UC_STRING) 1631 ucv_object_add(scope, ucv_string_get(name), ucv_get(v)); 1632 1633 ucv_put(name); 1634 uc_vm_stack_push(vm, v); 1635 } 1636 1637 static bool 1638 assert_mutable_value(uc_vm_t *vm, uc_value_t *val) 1639 { 1640 if (ucv_is_constant(val)) { 1641 uc_vm_stack_push(vm, NULL); 1642 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 1643 "%s value is immutable", 1644 ucv_typename(val)); 1645 1646 return false; 1647 } 1648 1649 return true; 1650 } 1651 1652 static void 1653 uc_vm_insn_store_val(uc_vm_t *vm, uc_vm_insn_t insn) 1654 { 1655 uc_value_t *v = uc_vm_stack_pop(vm); 1656 uc_value_t *k = uc_vm_stack_pop(vm); 1657 uc_value_t *o = uc_vm_stack_pop(vm); 1658 1659 switch (ucv_type(o)) { 1660 case UC_OBJECT: 1661 case UC_ARRAY: 1662 case UC_RESOURCE: 1663 if (assert_mutable_value(vm, o)) { 1664 /* ucv_key_set() retains the stored value on its own and returns a 1665 * reference to it, which becomes the value of the assignment; for 1666 * resources it dispatches a __set__ metamethod when present. In 1667 * strict mode it raises a type error when a non-index property 1668 * store on an array would otherwise be silently dropped. */ 1669 uc_vm_stack_push(vm, ucv_key_set(vm, o, k, v)); 1670 } 1671 1672 break; 1673 1674 default: 1675 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 1676 "attempt to set property on %s value", 1677 ucv_typename(o)); 1678 } 1679 1680 ucv_put(v); 1681 ucv_put(o); 1682 ucv_put(k); 1683 } 1684 1685 static void 1686 uc_vm_insn_store_upval(uc_vm_t *vm, uc_vm_insn_t insn) 1687 { 1688 uc_callframe_t *frame = uc_vm_current_frame(vm); 1689 uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; 1690 uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); 1691 1692 if (ref->closed) { 1693 ucv_put(ref->value); 1694 ref->value = val; 1695 } 1696 else { 1697 uc_vm_stack_set(vm, ref->slot, val); 1698 } 1699 } 1700 1701 static void 1702 uc_vm_insn_store_local(uc_vm_t *vm, uc_vm_insn_t insn) 1703 { 1704 uc_callframe_t *frame = uc_vm_current_frame(vm); 1705 uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); 1706 1707 uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val); 1708 } 1709 1710 static int64_t 1711 int64(uc_value_t *nv, uint64_t *u64) 1712 { 1713 int64_t n; 1714 1715 n = ucv_int64_get(nv); 1716 *u64 = 0; 1717 1718 if (errno == ERANGE) { 1719 n = INT64_MAX; 1720 *u64 = ucv_uint64_get(nv); 1721 } 1722 1723 return n; 1724 } 1725 1726 static uint64_t 1727 abs64(int64_t n) 1728 { 1729 if (n == INT64_MIN) 1730 return 0x8000000000000000ULL; 1731 1732 if (n < 0) 1733 return -n; 1734 1735 return n; 1736 } 1737 1738 1739 static uc_value_t * 1740 uc_vm_value_bitop(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand) 1741 { 1742 uc_value_t *nv1, *nv2, *rv = NULL; 1743 uint64_t u1, u2; 1744 int64_t n1, n2; 1745 1746 nv1 = ucv_to_number(value); 1747 nv2 = ucv_to_number(operand); 1748 1749 n1 = int64(nv1, &u1); 1750 n2 = int64(nv2, &u2); 1751 1752 if (n1 < 0 || n2 < 0) { 1753 switch (operation) { 1754 case I_LSHIFT: 1755 rv = ucv_int64_new(n1 << n2); 1756 break; 1757 1758 case I_RSHIFT: 1759 rv = ucv_int64_new(n1 >> n2); 1760 break; 1761 1762 case I_BAND: 1763 rv = ucv_int64_new(n1 & n2); 1764 break; 1765 1766 case I_BXOR: 1767 rv = ucv_int64_new(n1 ^ n2); 1768 break; 1769 1770 case I_BOR: 1771 rv = ucv_int64_new(n1 | n2); 1772 break; 1773 1774 default: 1775 break; 1776 } 1777 } 1778 else { 1779 if (!u1) u1 = (uint64_t)n1; 1780 if (!u2) u2 = (uint64_t)n2; 1781 1782 switch (operation) { 1783 case I_LSHIFT: 1784 rv = ucv_uint64_new(u1 << (u2 % (sizeof(uint64_t) * CHAR_BIT))); 1785 break; 1786 1787 case I_RSHIFT: 1788 rv = ucv_uint64_new(u1 >> (u2 % (sizeof(uint64_t) * CHAR_BIT))); 1789 break; 1790 1791 case I_BAND: 1792 rv = ucv_uint64_new(u1 & u2); 1793 break; 1794 1795 case I_BXOR: 1796 rv = ucv_uint64_new(u1 ^ u2); 1797 break; 1798 1799 case I_BOR: 1800 rv = ucv_uint64_new(u1 | u2); 1801 break; 1802 1803 default: 1804 break; 1805 } 1806 } 1807 1808 ucv_put(nv1); 1809 ucv_put(nv2); 1810 1811 return rv; 1812 } 1813 1814 static uc_value_t * 1815 uc_vm_string_concat(uc_vm_t *vm, uc_value_t *v1, uc_value_t *v2) 1816 { 1817 char buf[sizeof(void *)], *s1, *s2, *str; 1818 uc_value_t *ustr; 1819 uc_stringbuf_t *sbuf; 1820 size_t l1, l2; 1821 1822 /* optimize cases for string+string concat... */ 1823 if (ucv_type(v1) == UC_STRING && ucv_type(v2) == UC_STRING) { 1824 s1 = ucv_string_get(v1); 1825 s2 = ucv_string_get(v2); 1826 l1 = ucv_string_length(v1); 1827 l2 = ucv_string_length(v2); 1828 1829 /* ... result fits into a tagged pointer */ 1830 if (l1 + l2 + 1 < sizeof(buf)) { 1831 memcpy(&buf[0], s1, l1); 1832 memcpy(&buf[l1], s2, l2); 1833 1834 return ucv_string_new_length(buf, l1 + l2); 1835 } 1836 else { 1837 ustr = ucv_string_alloc(&str, l1 + l2); 1838 memcpy(&str[0], s1, l1); 1839 memcpy(&str[l1], s2, l2); 1840 1841 return ustr; 1842 } 1843 } 1844 1845 sbuf = ucv_stringbuf_new(); 1846 1847 ucv_to_stringbuf(vm, sbuf, v1, false); 1848 ucv_to_stringbuf(vm, sbuf, v2, false); 1849 1850 return ucv_stringbuf_finish(sbuf); 1851 } 1852 1853 static uint64_t 1854 upow64(uint64_t base, uint64_t exponent) 1855 { 1856 uint64_t result = 1; 1857 1858 while (exponent) { 1859 if (exponent & 1) 1860 result *= base; 1861 1862 exponent >>= 1; 1863 base *= base; 1864 } 1865 1866 return result; 1867 } 1868 1869 static uc_value_t * 1870 uc_vm_value_arith(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand) 1871 { 1872 uc_value_t *nv1, *nv2, *rv = NULL; 1873 uint64_t u1, u2; 1874 int64_t n1, n2; 1875 double d1, d2; 1876 1877 if (operation == I_LSHIFT || operation == I_RSHIFT || 1878 operation == I_BAND || operation == I_BXOR || operation == I_BOR) 1879 return uc_vm_value_bitop(vm, operation, value, operand); 1880 1881 if (operation == I_ADD && (ucv_type(value) == UC_STRING || ucv_type(operand) == UC_STRING)) 1882 return uc_vm_string_concat(vm, value, operand); 1883 1884 nv1 = ucv_to_number(value); 1885 nv2 = ucv_to_number(operand); 1886 1887 /* any operation involving NaN results in NaN */ 1888 if (!nv1 || !nv2) { 1889 ucv_put(nv1); 1890 ucv_put(nv2); 1891 1892 return ucv_double_new(NAN); 1893 } 1894 if (ucv_type(nv1) == UC_DOUBLE || ucv_type(nv2) == UC_DOUBLE) { 1895 d1 = ucv_double_get(nv1); 1896 d2 = ucv_double_get(nv2); 1897 1898 switch (operation) { 1899 case I_ADD: 1900 case I_PLUS: 1901 rv = ucv_double_new(d1 + d2); 1902 break; 1903 1904 case I_SUB: 1905 case I_MINUS: 1906 rv = ucv_double_new(d1 - d2); 1907 break; 1908 1909 case I_MUL: 1910 rv = ucv_double_new(d1 * d2); 1911 break; 1912 1913 case I_DIV: 1914 if (d2 == 0.0) 1915 rv = ucv_double_new(INFINITY); 1916 else if (isnan(d2)) 1917 rv = ucv_double_new(NAN); 1918 else if (!isfinite(d2)) 1919 rv = ucv_double_new(isfinite(d1) ? 0.0 : NAN); 1920 else 1921 rv = ucv_double_new(d1 / d2); 1922 1923 break; 1924 1925 case I_MOD: 1926 rv = ucv_double_new(fmod(d1, d2)); 1927 break; 1928 1929 case I_EXP: 1930 rv = ucv_double_new(pow(d1, d2)); 1931 break; 1932 1933 default: 1934 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 1935 "undefined arithmetic operation %d", 1936 operation); 1937 break; 1938 } 1939 } 1940 else { 1941 n1 = int64(nv1, &u1); 1942 n2 = int64(nv2, &u2); 1943 1944 switch (operation) { 1945 case I_ADD: 1946 case I_PLUS: 1947 if (n1 < 0 || n2 < 0) { 1948 if (u1) 1949 rv = ucv_uint64_new(u1 - abs64(n2)); 1950 else if (u2) 1951 rv = ucv_uint64_new(u2 - abs64(n1)); 1952 else 1953 rv = ucv_int64_new(n1 + n2); 1954 } 1955 else { 1956 if (!u1) u1 = (uint64_t)n1; 1957 if (!u2) u2 = (uint64_t)n2; 1958 1959 rv = ucv_uint64_new(u1 + u2); 1960 } 1961 1962 break; 1963 1964 case I_SUB: 1965 case I_MINUS: 1966 if (n1 < 0 && n2 < 0) { 1967 if (n1 > n2) 1968 rv = ucv_uint64_new(abs64(n2) - abs64(n1)); 1969 else 1970 rv = ucv_int64_new(n1 - n2); 1971 } 1972 else if (n1 >= 0 && n2 >= 0) { 1973 if (!u1) u1 = (uint64_t)n1; 1974 if (!u2) u2 = (uint64_t)n2; 1975 1976 if (u2 > u1) 1977 rv = ucv_int64_new(-(u2 - u1)); 1978 else 1979 rv = ucv_uint64_new(u1 - u2); 1980 } 1981 else if (n1 >= 0) { 1982 if (!u1) u1 = (uint64_t)n1; 1983 1984 rv = ucv_uint64_new(u1 + abs64(n2)); 1985 } 1986 else { 1987 rv = ucv_int64_new(n1 - n2); 1988 } 1989 1990 break; 1991 1992 case I_MUL: 1993 if (n1 < 0 && n2 < 0) { 1994 rv = ucv_uint64_new(abs64(n1) * abs64(n2)); 1995 } 1996 else if (n1 >= 0 && n2 >= 0) { 1997 if (!u1) u1 = (uint64_t)n1; 1998 if (!u2) u2 = (uint64_t)n2; 1999 2000 rv = ucv_uint64_new(u1 * u2); 2001 } 2002 else { 2003 rv = ucv_int64_new(n1 * n2); 2004 } 2005 2006 break; 2007 2008 case I_DIV: 2009 if (n2 == 0) { 2010 rv = ucv_double_new(INFINITY); 2011 } 2012 else if (n1 == INT64_MIN && n2 == -1) { 2013 /* the mathematical result 2^63 only fits into uint64_t; 2014 * the signed division would trap with SIGFPE */ 2015 rv = ucv_uint64_new((uint64_t)INT64_MAX + 1); 2016 } 2017 else if (n1 < 0 || n2 < 0) { 2018 rv = ucv_int64_new(n1 / n2); 2019 } 2020 else { 2021 if (!u1) u1 = (uint64_t)n1; 2022 if (!u2) u2 = (uint64_t)n2; 2023 2024 rv = ucv_uint64_new(u1 / u2); 2025 } 2026 2027 break; 2028 2029 case I_MOD: 2030 if (n2 == 0) { 2031 rv = ucv_double_new(NAN); 2032 } 2033 else if (n1 == INT64_MIN && n2 == -1) { 2034 /* the signed modulo would trap with SIGFPE */ 2035 rv = ucv_int64_new(0); 2036 } 2037 else if (n1 < 0 || n2 < 0) { 2038 rv = ucv_int64_new(n1 % n2); 2039 } 2040 else { 2041 if (!u1) u1 = (uint64_t)n1; 2042 if (!u2) u2 = (uint64_t)n2; 2043 2044 rv = ucv_uint64_new(u1 % u2); 2045 } 2046 2047 break; 2048 2049 case I_EXP: 2050 if (n1 < 0 || n2 < 0) { 2051 /* the result is negative iff the base is negative and the 2052 * exponent is odd */ 2053 if (n2 < 0) 2054 rv = ucv_double_new(((n1 < 0 && (n2 & 1)) ? -1.0 : 1.0) / 2055 (double)upow64(abs64(n1), abs64(n2))); 2056 else if (n2 & 1) 2057 rv = ucv_int64_new((int64_t)-upow64(abs64(n1), abs64(n2))); 2058 else 2059 rv = ucv_uint64_new(upow64(abs64(n1), abs64(n2))); 2060 } 2061 else { 2062 if (!u1) u1 = (uint64_t)n1; 2063 if (!u2) u2 = (uint64_t)n2; 2064 2065 rv = ucv_uint64_new(upow64(u1, u2)); 2066 } 2067 2068 break; 2069 2070 default: 2071 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 2072 "undefined arithmetic operation %d", 2073 operation); 2074 break; 2075 } 2076 } 2077 2078 ucv_put(nv1); 2079 ucv_put(nv2); 2080 2081 return rv; 2082 } 2083 2084 static void 2085 uc_vm_insn_update_var(uc_vm_t *vm, uc_vm_insn_t insn) 2086 { 2087 uc_value_t *name, *val = NULL, *inc = uc_vm_stack_pop(vm); 2088 uc_value_t *scope, *next; 2089 bool found; 2090 2091 scope = vm->globals; 2092 name = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32 & 0x00FFFFFF); 2093 2094 assert(ucv_type(name) == UC_STRING); 2095 2096 while (true) { 2097 val = ucv_object_get(scope, ucv_string_get(name), &found); 2098 2099 if (found) 2100 break; 2101 2102 next = ucv_prototype_get(scope); 2103 2104 if (!next) { 2105 if (uc_vm_is_strict(vm)) { 2106 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 2107 "access to undeclared variable %s", 2108 ucv_string_get(name)); 2109 ucv_put(name); 2110 ucv_put(inc); 2111 2112 return; 2113 } 2114 2115 break; 2116 } 2117 2118 scope = next; 2119 } 2120 2121 val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc); 2122 2123 ucv_object_add(scope, ucv_string_get(name), ucv_get(val)); 2124 uc_vm_stack_push(vm, val); 2125 2126 ucv_put(name); 2127 ucv_put(inc); 2128 } 2129 2130 static void 2131 uc_vm_insn_update_val(uc_vm_t *vm, uc_vm_insn_t insn) 2132 { 2133 uc_value_t *inc = uc_vm_stack_pop(vm); 2134 uc_value_t *k = uc_vm_stack_pop(vm); 2135 uc_value_t *v = uc_vm_stack_pop(vm); 2136 uc_value_t *val = NULL; 2137 uc_vm_insn_t op; 2138 2139 switch (ucv_type(v)) { 2140 case UC_OBJECT: 2141 case UC_ARRAY: 2142 case UC_RESOURCE: 2143 if (assert_mutable_value(vm, v)) { 2144 uc_value_t *nv, *rv; 2145 2146 /* reading the property may dispatch a __get__ metamethod which runs 2147 * on the current stack, clobbers vm->arg and may collect garbage, so 2148 * remember the operation and keep the operands reachable */ 2149 op = vm->arg.u8; 2150 uc_vm_stack_push(vm, ucv_get(inc)); 2151 2152 val = ucv_key_get(vm, v, k); 2153 uc_vm_stack_push(vm, ucv_get(val)); 2154 2155 nv = uc_vm_value_arith(vm, op, val, inc); 2156 2157 ucv_put(uc_vm_stack_pop(vm)); 2158 ucv_put(uc_vm_stack_pop(vm)); 2159 2160 /* an aborted read leaves nothing to store; the exception it raised is 2161 * left to propagate instead of overwriting the property */ 2162 rv = vm->exception.type != EXCEPTION_NONE ? NULL : ucv_key_set(vm, v, k, nv); 2163 2164 /* the store keeps a reference of its own; rv is the value of the 2165 * update expression, null if storing failed */ 2166 ucv_put(nv); 2167 2168 uc_vm_stack_push(vm, rv); 2169 } 2170 2171 break; 2172 2173 default: 2174 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 2175 "left-hand side expression is %s", 2176 v ? "not an array or object" : "null"); 2177 2178 break; 2179 } 2180 2181 ucv_put(val); 2182 ucv_put(inc); 2183 ucv_put(v); 2184 ucv_put(k); 2185 } 2186 2187 static void 2188 uc_vm_insn_update_upval(uc_vm_t *vm, uc_vm_insn_t insn) 2189 { 2190 uc_callframe_t *frame = uc_vm_current_frame(vm); 2191 size_t slot = vm->arg.u32 & 0x00FFFFFF; 2192 uc_upvalref_t *ref = frame->closure->upvals[slot]; 2193 uc_value_t *inc = uc_vm_stack_pop(vm); 2194 uc_value_t *val; 2195 2196 if (ref->closed) 2197 val = ref->value; 2198 else 2199 val = vm->stack.entries[ref->slot]; 2200 2201 val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc); 2202 2203 uc_vm_stack_push(vm, val); 2204 2205 ucv_put(inc); 2206 2207 if (ref->closed) { 2208 ucv_put(ref->value); 2209 ref->value = ucv_get(uc_vm_stack_peek(vm, 0)); 2210 } 2211 else { 2212 uc_vm_stack_set(vm, ref->slot, ucv_get(uc_vm_stack_peek(vm, 0))); 2213 } 2214 } 2215 2216 static void 2217 uc_vm_insn_update_local(uc_vm_t *vm, uc_vm_insn_t insn) 2218 { 2219 uc_callframe_t *frame = uc_vm_current_frame(vm); 2220 size_t slot = vm->arg.u32 & 0x00FFFFFF; 2221 uc_value_t *inc = uc_vm_stack_pop(vm); 2222 uc_value_t *val; 2223 2224 val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, 2225 vm->stack.entries[frame->stackframe + slot], inc); 2226 2227 uc_vm_stack_push(vm, val); 2228 2229 ucv_put(inc); 2230 uc_vm_stack_set(vm, frame->stackframe + slot, ucv_get(uc_vm_stack_peek(vm, 0))); 2231 } 2232 2233 static void 2234 uc_vm_insn_narr(uc_vm_t *vm, uc_vm_insn_t insn) 2235 { 2236 uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32); 2237 2238 uc_vm_stack_push(vm, arr); 2239 } 2240 2241 static void 2242 uc_vm_insn_parr(uc_vm_t *vm, uc_vm_insn_t insn) 2243 { 2244 uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32); 2245 size_t idx; 2246 2247 for (idx = 0; idx < vm->arg.u32; idx++) 2248 ucv_array_push(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)); 2249 2250 for (idx = 0; idx < vm->arg.u32; idx++) 2251 uc_vm_stack_pop(vm); 2252 2253 //uc_vm_shrink(state, vm->arg.u32); 2254 } 2255 2256 static void 2257 uc_vm_insn_marr(uc_vm_t *vm, uc_vm_insn_t insn) 2258 { 2259 uc_value_t *src = uc_vm_stack_pop(vm); 2260 uc_value_t *dst = uc_vm_stack_peek(vm, 0); 2261 size_t i; 2262 char *s; 2263 2264 if (ucv_type(src) != UC_ARRAY) { 2265 s = ucv_to_string(vm, src); 2266 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); 2267 ucv_put(src); 2268 free(s); 2269 2270 return; 2271 } 2272 2273 for (i = 0; i < ucv_array_length(src); i++) 2274 ucv_array_push(dst, ucv_get(ucv_array_get(src, i))); 2275 2276 ucv_put(src); 2277 } 2278 2279 static void 2280 uc_vm_insn_nobj(uc_vm_t *vm, uc_vm_insn_t insn) 2281 { 2282 uc_value_t *obj = ucv_object_new(vm); 2283 2284 uc_vm_stack_push(vm, obj); 2285 } 2286 2287 static void 2288 uc_vm_insn_sobj(uc_vm_t *vm, uc_vm_insn_t insn) 2289 { 2290 uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); 2291 size_t idx; 2292 2293 /* object literals create own keys, a __set__ metamethod of the object under 2294 * construction must not intercept the keys it is built from */ 2295 for (idx = 0; idx < vm->arg.u32; idx += 2) 2296 ucv_put(ucv_key_rawset(vm, obj, 2297 uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1), 2298 uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); 2299 2300 for (idx = 0; idx < vm->arg.u32; idx++) 2301 ucv_put(uc_vm_stack_pop(vm)); 2302 } 2303 2304 static void 2305 uc_vm_insn_mobj(uc_vm_t *vm, uc_vm_insn_t insn) 2306 { 2307 uc_value_t *src = uc_vm_stack_pop(vm); 2308 uc_value_t *dst = uc_vm_stack_peek(vm, 0); 2309 size_t i; 2310 char *s; 2311 2312 switch (ucv_type(src)) { 2313 case UC_OBJECT: 2314 ; /* a label can only be part of a statement and a declaration is not a statement */ 2315 ucv_object_foreach(src, k, v) 2316 ucv_object_add(dst, k, ucv_get(v)); 2317 2318 ucv_put(src); 2319 break; 2320 2321 case UC_ARRAY: 2322 for (i = 0; i < ucv_array_length(src); i++) { 2323 xasprintf(&s, "%zu", i); 2324 ucv_object_add(dst, s, ucv_get(ucv_array_get(src, i))); 2325 free(s); 2326 } 2327 2328 ucv_put(src); 2329 break; 2330 2331 default: 2332 s = ucv_to_string(vm, src); 2333 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Value (%s) is not iterable", s); 2334 free(s); 2335 2336 break; 2337 } 2338 } 2339 2340 static void 2341 uc_vm_insn_arith(uc_vm_t *vm, uc_vm_insn_t insn) 2342 { 2343 uc_value_t *r2 = uc_vm_stack_pop(vm); 2344 uc_value_t *r1 = uc_vm_stack_pop(vm); 2345 uc_value_t *rv; 2346 2347 rv = uc_vm_value_arith(vm, insn, r1, r2); 2348 2349 ucv_put(r1); 2350 ucv_put(r2); 2351 2352 uc_vm_stack_push(vm, rv); 2353 } 2354 2355 static void 2356 uc_vm_insn_plus_minus(uc_vm_t *vm, uc_vm_insn_t insn) 2357 { 2358 uc_value_t *v = uc_vm_stack_pop(vm), *nv; 2359 bool is_sub = (insn == I_MINUS); 2360 int64_t n; 2361 double d; 2362 2363 if (ucv_type(v) == UC_STRING) { 2364 nv = uc_number_parse(ucv_string_get(v), NULL); 2365 2366 if (nv) { 2367 ucv_put(v); 2368 v = nv; 2369 } 2370 } 2371 2372 switch (ucv_type(v)) { 2373 case UC_INTEGER: 2374 n = ucv_int64_get(v); 2375 2376 /* numeric value is in range 9223372036854775808..18446744073709551615 */ 2377 if (errno == ERANGE) { 2378 if (is_sub) 2379 /* make negation of large numeric value result in smallest negative value */ 2380 uc_vm_stack_push(vm, ucv_int64_new(INT64_MIN)); 2381 else 2382 /* for positive number coercion return value as-is */ 2383 uc_vm_stack_push(vm, ucv_get(v)); 2384 } 2385 2386 /* numeric value is in range -9223372036854775808..9223372036854775807 */ 2387 else { 2388 if (is_sub) { 2389 if (n == INT64_MIN) 2390 /* make negation of minimum value result in maximum signed positive value */ 2391 uc_vm_stack_push(vm, ucv_int64_new(INT64_MAX)); 2392 else 2393 /* for all other values flip the sign */ 2394 uc_vm_stack_push(vm, ucv_int64_new(-n)); 2395 } 2396 else { 2397 /* for positive number coercion return value as-is */ 2398 uc_vm_stack_push(vm, ucv_get(v)); 2399 } 2400 } 2401 2402 break; 2403 2404 case UC_DOUBLE: 2405 d = ucv_double_get(v); 2406 uc_vm_stack_push(vm, ucv_double_new(is_sub ? -d : d)); 2407 break; 2408 2409 case UC_BOOLEAN: 2410 n = (int64_t)ucv_boolean_get(v); 2411 uc_vm_stack_push(vm, ucv_int64_new(is_sub ? -n : n)); 2412 break; 2413 2414 case UC_NULL: 2415 uc_vm_stack_push(vm, ucv_int64_new(0)); 2416 break; 2417 2418 default: 2419 uc_vm_stack_push(vm, ucv_double_new(NAN)); 2420 } 2421 2422 ucv_put(v); 2423 } 2424 2425 static void 2426 uc_vm_insn_bitop(uc_vm_t *vm, uc_vm_insn_t insn) 2427 { 2428 uc_value_t *r2 = uc_vm_stack_pop(vm); 2429 uc_value_t *r1 = uc_vm_stack_pop(vm); 2430 uc_value_t *rv; 2431 2432 rv = uc_vm_value_bitop(vm, insn, r1, r2); 2433 2434 ucv_put(r1); 2435 ucv_put(r2); 2436 2437 uc_vm_stack_push(vm, rv); 2438 } 2439 2440 static void 2441 uc_vm_insn_complement(uc_vm_t *vm, uc_vm_insn_t insn) 2442 { 2443 uc_value_t *v = uc_vm_stack_pop(vm); 2444 uc_value_t *nv; 2445 uint64_t u; 2446 int64_t n; 2447 2448 nv = ucv_to_number(v); 2449 n = int64(nv, &u); 2450 2451 if (n < 0) { 2452 uc_vm_stack_push(vm, ucv_int64_new(~n)); 2453 } 2454 else { 2455 if (!u) u = (uint64_t)n; 2456 2457 uc_vm_stack_push(vm, ucv_uint64_new(~u)); 2458 } 2459 2460 ucv_put(nv); 2461 ucv_put(v); 2462 } 2463 2464 static void 2465 uc_vm_insn_rel(uc_vm_t *vm, uc_vm_insn_t insn) 2466 { 2467 uc_value_t *r2 = uc_vm_stack_pop(vm); 2468 uc_value_t *r1 = uc_vm_stack_pop(vm); 2469 2470 bool res = ucv_compare(insn, r1, r2, NULL); 2471 2472 ucv_put(r1); 2473 ucv_put(r2); 2474 2475 uc_vm_stack_push(vm, ucv_boolean_new(res)); 2476 } 2477 2478 /* Test whether `key` names a property of `scope` or of anything in its 2479 * prototype chain, the way a property read resolves it - but without 2480 * dispatching __get__, so a purely virtual property stays hidden. */ 2481 static bool 2482 uc_vm_key_exists(uc_value_t *scope, uc_value_t *key) 2483 { 2484 uc_value_t *o; 2485 bool found = false; 2486 2487 if (ucv_type(key) != UC_STRING) 2488 return false; 2489 2490 for (o = scope; o != NULL && !found; o = ucv_prototype_get(o)) 2491 ucv_object_get(o, ucv_string_get(key), &found); 2492 2493 return found; 2494 } 2495 2496 static void 2497 uc_vm_insn_in(uc_vm_t *vm, uc_vm_insn_t insn) 2498 { 2499 uc_value_t *r2 = uc_vm_stack_pop(vm); 2500 uc_value_t *r1 = uc_vm_stack_pop(vm); 2501 uc_value_t *item; 2502 size_t arrlen, arridx; 2503 bool found = false; 2504 2505 switch (ucv_type(r2)) { 2506 case UC_ARRAY: 2507 /* value membership: is r1 one of the array elements? */ 2508 for (arridx = 0, arrlen = ucv_array_length(r2); 2509 arridx < arrlen; arridx++) { 2510 item = ucv_array_get(r2, arridx); 2511 2512 if (uc_vm_test_strict_equality(r1, item, true)) { 2513 found = true; 2514 break; 2515 } 2516 } 2517 2518 /* arrays can carry a prototype providing the tested key as well */ 2519 if (!found) 2520 found = uc_vm_key_exists(r2, r1); 2521 2522 break; 2523 2524 case UC_OBJECT: 2525 found = uc_vm_key_exists(r2, r1); 2526 2527 break; 2528 2529 default: 2530 found = false; 2531 } 2532 2533 ucv_put(r1); 2534 ucv_put(r2); 2535 2536 uc_vm_stack_push(vm, ucv_boolean_new(found)); 2537 } 2538 2539 static void 2540 uc_vm_insn_equality(uc_vm_t *vm, uc_vm_insn_t insn) 2541 { 2542 uc_value_t *r2 = uc_vm_stack_pop(vm); 2543 uc_value_t *r1 = uc_vm_stack_pop(vm); 2544 bool equal = uc_vm_test_strict_equality(r1, r2, false); 2545 2546 ucv_put(r1); 2547 ucv_put(r2); 2548 2549 uc_vm_stack_push(vm, ucv_boolean_new((insn == I_EQS) ? equal : !equal)); 2550 } 2551 2552 static void 2553 uc_vm_insn_not(uc_vm_t *vm, uc_vm_insn_t insn) 2554 { 2555 uc_value_t *r1 = uc_vm_stack_pop(vm); 2556 2557 uc_vm_stack_push(vm, ucv_boolean_new(!ucv_is_truish(r1))); 2558 ucv_put(r1); 2559 } 2560 2561 static void 2562 uc_vm_insn_jmp(uc_vm_t *vm, uc_vm_insn_t insn) 2563 { 2564 uc_callframe_t *frame = uc_vm_current_frame(vm); 2565 uc_chunk_t *chunk = uc_vm_frame_chunk(frame); 2566 int32_t addr = vm->arg.s32; 2567 2568 /* ip already has been incremented */ 2569 addr -= 5; 2570 2571 if (frame->ip + addr < chunk->entries || 2572 frame->ip + addr >= chunk->entries + chunk->count) { 2573 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range"); 2574 return; 2575 } 2576 2577 frame->ip += addr; 2578 } 2579 2580 static void 2581 uc_vm_insn_jmpz(uc_vm_t *vm, uc_vm_insn_t insn) 2582 { 2583 uc_callframe_t *frame = uc_vm_current_frame(vm); 2584 uc_chunk_t *chunk = uc_vm_frame_chunk(frame); 2585 uc_value_t *v = uc_vm_stack_pop(vm); 2586 int32_t addr = vm->arg.s32; 2587 2588 /* ip already has been incremented */ 2589 addr -= 5; 2590 2591 if (frame->ip + addr < chunk->entries || 2592 frame->ip + addr >= chunk->entries + chunk->count) { 2593 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range"); 2594 return; 2595 } 2596 2597 if (!ucv_is_truish(v)) 2598 frame->ip += addr; 2599 2600 ucv_put(v); 2601 } 2602 2603 static void 2604 uc_vm_insn_jmpnt(uc_vm_t *vm, uc_vm_insn_t insn) 2605 { 2606 uc_callframe_t *frame = uc_vm_current_frame(vm); 2607 uc_chunk_t *chunk = uc_vm_frame_chunk(frame); 2608 int16_t addr = (vm->arg.u32 & 0xffff) - 0x7fff; 2609 uint16_t types = (vm->arg.u32 >> 16) & 0x1fff; 2610 uint8_t depth = (vm->arg.u32 >> 29) & 0x7; 2611 uc_value_t *v = uc_vm_stack_peek(vm, 0); 2612 size_t i; 2613 2614 /* ip already has been incremented */ 2615 addr -= 5; 2616 2617 if (frame->ip + addr < chunk->entries || 2618 frame->ip + addr >= chunk->entries + chunk->count) { 2619 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "jump target out of range"); 2620 return; 2621 } 2622 2623 if (!(types & (1u << ucv_type(v)))) { 2624 for (i = 0; i <= depth; i++) 2625 ucv_put(uc_vm_stack_pop(vm)); 2626 2627 uc_vm_stack_push(vm, NULL); 2628 frame->ip += addr; 2629 } 2630 } 2631 2632 2633 static void 2634 uc_vm_object_iterator_free(void *ud) 2635 { 2636 uc_object_iterator_t *iter = ud; 2637 2638 uc_list_remove(&iter->list); 2639 } 2640 2641 static uc_resource_type_t uc_vm_object_iterator_type = { 2642 .name = "object iterator", 2643 .free = uc_vm_object_iterator_free 2644 }; 2645 2646 static bool 2647 uc_vm_object_iterator_next(uc_vm_t *vm, uc_vm_insn_t insn, 2648 uc_value_t *k, uc_value_t *v) 2649 { 2650 uc_resource_t *res = ucv_as_resource(k); 2651 uc_object_t *obj = ucv_as_object(v); 2652 uc_object_iterator_t *iter; 2653 2654 if (!res) { 2655 /* object is empty */ 2656 if (!obj->table->head) 2657 return false; 2658 2659 res = xalloc(sizeof(*res) + sizeof(uc_object_iterator_t)); 2660 res->header.type = UC_RESOURCE; 2661 res->header.refcount = 1; 2662 res->type = &uc_vm_object_iterator_type; 2663 2664 iter = res->data = (char *)res + sizeof(*res); 2665 iter->table = obj->table; 2666 iter->u.pos = obj->table->head; 2667 2668 uc_list_insert(&uc_thread_context_get()->object_iterators, &iter->list); 2669 } 2670 else if (ucv_type(k) == UC_RESOURCE && 2671 res->type == &uc_vm_object_iterator_type && res->data != NULL) { 2672 2673 iter = res->data; 2674 } 2675 else { 2676 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid object iterator"); 2677 2678 return false; 2679 } 2680 2681 /* no next key */ 2682 if (!iter->u.pos) { 2683 uc_list_remove(&iter->list); 2684 2685 return false; 2686 } 2687 2688 uc_vm_stack_push(vm, ucv_string_new(iter->u.pos->k)); 2689 2690 if (insn == I_NEXTKV) 2691 uc_vm_stack_push(vm, ucv_get((uc_value_t *)iter->u.pos->v)); 2692 2693 uc_vm_stack_push(vm, &res->header); 2694 ucv_put(v); 2695 2696 iter->u.pos = iter->u.pos->next; 2697 2698 return true; 2699 } 2700 2701 static bool 2702 uc_vm_array_iterator_next(uc_vm_t *vm, uc_vm_insn_t insn, 2703 uc_value_t *k, uc_value_t *v) 2704 { 2705 uint64_t n; 2706 2707 if (!k) { 2708 /* array is empty */ 2709 if (!ucv_array_length(v)) 2710 return false; 2711 2712 k = ucv_resource_new(NULL, NULL); 2713 n = 0; 2714 } 2715 else if (ucv_type(k) == UC_RESOURCE) { 2716 n = (uintptr_t)ucv_resource_data(k, NULL); 2717 } 2718 else { 2719 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid array iterator"); 2720 2721 return false; 2722 } 2723 2724 /* no next index */ 2725 if (n >= ucv_array_length(v)) 2726 return false; 2727 2728 if (insn == I_NEXTKV) 2729 uc_vm_stack_push(vm, ucv_uint64_new(n)); 2730 2731 uc_vm_stack_push(vm, ucv_get(ucv_array_get(v, n))); 2732 2733 uc_vm_stack_push(vm, k); 2734 ucv_put(v); 2735 2736 ucv_as_resource(k)->data = (void *)(uintptr_t)(n + 1); 2737 2738 return true; 2739 } 2740 2741 static void 2742 uc_vm_insn_next(uc_vm_t *vm, uc_vm_insn_t insn) 2743 { 2744 uc_value_t *k = uc_vm_stack_pop(vm); 2745 uc_value_t *v = uc_vm_stack_pop(vm); 2746 2747 switch (ucv_type(v)) { 2748 case UC_OBJECT: 2749 if (uc_vm_object_iterator_next(vm, insn, k, v)) 2750 return; 2751 2752 break; 2753 2754 case UC_ARRAY: 2755 if (uc_vm_array_iterator_next(vm, insn, k, v)) 2756 return; 2757 2758 break; 2759 2760 default: 2761 break; 2762 } 2763 2764 uc_vm_stack_push(vm, NULL); 2765 uc_vm_stack_push(vm, NULL); 2766 2767 if (insn == I_NEXTKV) 2768 uc_vm_stack_push(vm, NULL); 2769 2770 ucv_put(k); 2771 ucv_put(v); 2772 } 2773 2774 static void 2775 uc_vm_insn_close_upval(uc_vm_t *vm, uc_vm_insn_t insn) 2776 { 2777 uc_vm_close_upvals(vm, vm->stack.count - 1); 2778 ucv_put(uc_vm_stack_pop(vm)); 2779 } 2780 2781 static void 2782 uc_vm_insn_call(uc_vm_t *vm) 2783 { 2784 bool mcall = (vm->arg.u32 & 0x80000000); 2785 size_t nargs = (vm->arg.u32 & 0xffff); 2786 size_t nspreads = (vm->arg.u32 >> 16) & 0x7fff; 2787 uint8_t *ip = uc_vm_current_frame(vm)->ip + 2 * nspreads; 2788 uc_value_t *fno = uc_vm_stack_peek(vm, nargs); 2789 uc_value_t *ctx = NULL; 2790 bool tail; 2791 2792 if (!ucv_is_arrowfn(fno)) 2793 ctx = mcall ? uc_vm_stack_peek(vm, nargs + 1) : NULL; 2794 else if (vm->callframes.count > 0) 2795 ctx = uc_vm_current_frame(vm)->ctx; 2796 2797 /* a tail call is indicated by a 0x00 marker that the compiler emits 2798 * immediately after the enclosing I_RETURN. ip points just past the call's 2799 * operand span, so ip[0] is the I_RETURN and ip[1] the marker. Neither VM 2800 * executes the marker: older VMs return before reaching it, and this VM 2801 * jumps to the callee at the call site. */ 2802 tail = (ip[0] == I_RETURN) && (ip[1] == 0x00); 2803 2804 uc_vm_call_function(vm, ucv_get(ctx), ucv_get(fno), mcall, vm->arg.u32, tail); 2805 } 2806 2807 static void 2808 uc_vm_insn_print(uc_vm_t *vm, uc_vm_insn_t insn) 2809 { 2810 uc_value_t *v = uc_vm_stack_pop(vm); 2811 char *p; 2812 2813 switch (ucv_type(v)) { 2814 case UC_OBJECT: 2815 case UC_ARRAY: 2816 p = ucv_to_jsonstring(vm, v); 2817 fwrite(p, 1, strlen(p), vm->output); 2818 free(p); 2819 break; 2820 2821 case UC_STRING: 2822 fwrite(ucv_string_get(v), 1, ucv_string_length(v), vm->output); 2823 break; 2824 2825 case UC_NULL: 2826 break; 2827 2828 default: 2829 p = ucv_to_string(vm, v); 2830 fwrite(p, 1, strlen(p), vm->output); 2831 free(p); 2832 } 2833 2834 ucv_put(v); 2835 } 2836 2837 static void 2838 uc_vm_insn_delete(uc_vm_t *vm, uc_vm_insn_t insn) 2839 { 2840 uc_value_t *k = uc_vm_stack_pop(vm); 2841 uc_value_t *v = uc_vm_stack_pop(vm); 2842 bool rv; 2843 2844 switch (ucv_type(v)) { 2845 case UC_OBJECT: 2846 if (assert_mutable_value(vm, v)) { 2847 rv = ucv_key_delete(vm, v, k); 2848 uc_vm_stack_push(vm, ucv_boolean_new(rv)); 2849 } 2850 2851 break; 2852 2853 default: 2854 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 2855 "left-hand side expression is %s", 2856 v ? "not an object" : "null"); 2857 2858 break; 2859 } 2860 2861 ucv_put(k); 2862 ucv_put(v); 2863 } 2864 2865 static void 2866 uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn) 2867 { 2868 uc_callframe_t *frame = uc_vm_current_frame(vm); 2869 uc_program_t *prog = uc_vm_current_program(vm); 2870 uint16_t from = vm->arg.u32 & 0xffff; 2871 uint16_t to = vm->arg.u32 >> 16; 2872 uc_value_t *name, *modobj; 2873 uint32_t cidx; 2874 2875 /* is a wildcard import * from ... */ 2876 if (to == 0xffff) { 2877 to = from; 2878 modobj = ucv_object_new(vm); 2879 2880 /* instruction is followed by u16 containing the offset of the 2881 * first module export and `from` times u32 values containing 2882 * the constant indexes of the names */ 2883 for (from = frame->ip[0] * 0x100 + frame->ip[1], frame->ip += 2; 2884 from < prog->exports.count && to > 0; 2885 from++, to--) { 2886 2887 cidx = ( 2888 frame->ip[0] * 0x1000000UL + 2889 frame->ip[1] * 0x10000UL + 2890 frame->ip[2] * 0x100UL + 2891 frame->ip[3] 2892 ); 2893 2894 frame->ip += 4; 2895 2896 name = uc_program_get_constant(uc_vm_current_program(vm), cidx); 2897 2898 if (ucv_type(name) == UC_STRING && prog->exports.entries[from]) 2899 ucv_object_add(modobj, ucv_string_get(name), 2900 ucv_get(&prog->exports.entries[from]->header)); 2901 2902 ucv_put(name); 2903 } 2904 2905 ucv_set_constant(modobj, true); 2906 2907 uc_vm_stack_push(vm, modobj); 2908 } 2909 2910 /* module export available, patch into upvalue */ 2911 else if (from < prog->exports.count && prog->exports.entries[from]) { 2912 frame->closure->upvals[to] = prog->exports.entries[from]; 2913 ucv_get(&prog->exports.entries[from]->header); 2914 } 2915 2916 /* module export missing, e.g. due to premature return in module, 2917 * patch up dummy upvalue ref with `null` value */ 2918 else { 2919 frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0); 2920 frame->closure->upvals[to]->closed = true; 2921 } 2922 } 2923 2924 static void 2925 uc_vm_insn_export(uc_vm_t *vm, uc_vm_insn_t insn) 2926 { 2927 uc_callframe_t *frame = uc_vm_current_frame(vm); 2928 uc_program_t *prog = uc_vm_current_program(vm); 2929 uc_upvalref_t *ref = uc_vm_capture_upval(vm, frame->stackframe + vm->arg.u32); 2930 2931 uc_vector_push(&prog->exports, ref); 2932 ucv_get(&ref->header); 2933 } 2934 2935 static void 2936 uc_vm_insn_dynload(uc_vm_t *vm, uc_vm_insn_t insn) 2937 { 2938 uc_callframe_t *frame = uc_vm_current_frame(vm); 2939 uc_value_t *name, *export, *modscope, *modobj; 2940 uint16_t count = vm->arg.u32 & 0xffff; 2941 uint16_t to = vm->arg.u32 >> 16; 2942 uint32_t cidx; 2943 bool found; 2944 2945 /* Attempt to load module. Will raise exception on error */ 2946 name = uc_vm_stack_pop(vm); 2947 modscope = uc_require_library(vm, name, true); 2948 ucv_put(name); 2949 2950 if (!modscope) 2951 return; 2952 2953 /* If count is zero, we're doing a wildcard import. Shallow copy module 2954 * object, mark it constant and patch into the target upvalue. */ 2955 if (count == 0) { 2956 modobj = ucv_object_new(vm); 2957 2958 ucv_object_foreach(modscope, k, v) 2959 ucv_object_add(modobj, k, ucv_get(v)); 2960 2961 ucv_set_constant(modobj, true); 2962 2963 uc_vm_stack_push(vm, modobj); 2964 } 2965 2966 /* ... otherwise we're importing a specific list of names */ 2967 else { 2968 /* Instruction is followed by `count` times u32 values containing 2969 * the import name constant indexes */ 2970 while (count > 0) { 2971 cidx = ( 2972 frame->ip[0] * 0x1000000UL + 2973 frame->ip[1] * 0x10000UL + 2974 frame->ip[2] * 0x100UL + 2975 frame->ip[3] 2976 ); 2977 2978 frame->ip += 4; 2979 2980 name = uc_program_get_constant(uc_vm_current_program(vm), cidx); 2981 export = ucv_object_get(modscope, ucv_string_get(name), &found); 2982 2983 if (!found) { 2984 uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, 2985 "Module does not export %s", 2986 ucv_string_get(name)); 2987 2988 ucv_put(name); 2989 ucv_put(modscope); 2990 2991 return; 2992 } 2993 2994 ucv_put(name); 2995 2996 frame->closure->upvals[to] = (uc_upvalref_t *)ucv_upvalref_new(0); 2997 frame->closure->upvals[to]->closed = true; 2998 frame->closure->upvals[to]->value = ucv_get(export); 2999 3000 count--; 3001 to++; 3002 } 3003 } 3004 3005 ucv_put(modscope); 3006 } 3007 3008 static void 3009 uc_vm_gc_step(uc_vm_t *vm) 3010 { 3011 size_t curr_count = 0, prev_count = 0; 3012 uc_weakref_t *ref; 3013 3014 if (!(vm->gc_flags & UC_GC_ENABLED)) 3015 return; 3016 3017 if (vm->alloc_refs >= vm->gc_interval) { 3018 if (vm->trace) { 3019 for (ref = vm->values.next; ref != &vm->values; ref = ref->next) 3020 prev_count++; 3021 3022 ucv_gc(vm); 3023 3024 for (ref = vm->values.next; ref != &vm->values; ref = ref->next) 3025 curr_count++; 3026 3027 fprintf(stderr, "! GC reclaimed %zu object(s)\n", prev_count - curr_count); 3028 } 3029 else { 3030 ucv_gc(vm); 3031 } 3032 } 3033 } 3034 3035 static uc_value_t * 3036 uc_vm_callframe_pop(uc_vm_t *vm) 3037 { 3038 uc_callframe_t *frame = uc_vm_current_frame(vm); 3039 uc_value_t *retval; 3040 3041 /* close upvalues */ 3042 uc_vm_close_upvals(vm, frame->stackframe); 3043 3044 if (vm->stack.count > frame->stackframe) 3045 retval = uc_vm_stack_pop(vm); 3046 else 3047 retval = NULL; 3048 3049 /* reset function stack frame */ 3050 while (vm->stack.count > frame->stackframe) 3051 ucv_put(uc_vm_stack_pop(vm)); 3052 3053 /* for method calls, release context as well */ 3054 if (frame->mcall) 3055 ucv_put(uc_vm_stack_pop(vm)); 3056 3057 /* release function */ 3058 if (frame->closure) 3059 ucv_put(&frame->closure->header); 3060 3061 if (frame->cfunction) 3062 ucv_put(&frame->cfunction->header); 3063 3064 /* release context */ 3065 ucv_put(frame->ctx); 3066 3067 vm->callframes.count--; 3068 3069 return retval; 3070 } 3071 3072 static void 3073 uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex) 3074 { 3075 uc_value_t *ctx; 3076 3077 if (ex->type == EXCEPTION_USER) 3078 fprintf(stderr, "%s\n", ex->message); 3079 else 3080 fprintf(stderr, "%s: %s\n", 3081 exception_type_strings[ex->type] ? exception_type_strings[ex->type] : "Error", 3082 ex->message); 3083 3084 ctx = ucv_object_get(ucv_array_get(ex->stacktrace, 0), "context", NULL); 3085 3086 if (ctx) 3087 fprintf(stderr, "%s\n", ucv_string_get(ctx)); 3088 3089 fprintf(stderr, "\n"); 3090 } 3091 3092 uc_exception_type_t 3093 uc_vm_signal_dispatch(uc_vm_t *vm) 3094 { 3095 uc_exception_type_t ex; 3096 uc_value_t *handler; 3097 uint64_t mask; 3098 size_t i, j; 3099 int sig, rv; 3100 3101 /* Check whether the signal self-pipe was actually set up, rather than 3102 * re-checking config->setup_signal_handlers directly: the pipe may 3103 * have been lazily initialized on demand via 3104 * uc_vm_signal_handlers_ensure() after the fact (see lib/debug.c), 3105 * independent of what the original config requested. */ 3106 if (vm->signal.sigpipe[0] < 0) 3107 return EXCEPTION_NONE; 3108 3109 for (i = 0; i < ARRAY_SIZE(vm->signal.raised); i++) { 3110 if (!vm->signal.raised[i]) 3111 continue; 3112 3113 do { 3114 rv = read(vm->signal.sigpipe[0], &sig, sizeof(sig)); 3115 } while (rv > 0 || (rv == -1 && errno == EINTR)); 3116 3117 for (j = 0; j < 64; j++) { 3118 mask = 1ull << j; 3119 3120 if (vm->signal.raised[i] & mask) { 3121 vm->signal.raised[i] &= ~mask; 3122 3123 sig = i * 64 + j; 3124 handler = ucv_array_get(vm->signal.handler, sig); 3125 3126 if (ucv_is_callable(handler)) { 3127 uc_vm_stack_push(vm, ucv_get(handler)); 3128 uc_vm_stack_push(vm, ucv_int64_new(sig)); 3129 3130 ex = uc_vm_call(vm, false, 1); 3131 3132 if (ex != EXCEPTION_NONE) 3133 return ex; 3134 3135 ucv_put(uc_vm_stack_pop(vm)); 3136 } 3137 } 3138 } 3139 } 3140 3141 return EXCEPTION_NONE; 3142 } 3143 3144 static uc_vm_status_t 3145 uc_vm_exception_type_to_status(uc_vm_t *vm) 3146 { 3147 switch (vm->exception.type) { 3148 case EXCEPTION_NONE: return STATUS_OK; 3149 case EXCEPTION_EXIT: return STATUS_EXIT; 3150 case EXCEPTION_SYNTAX: return ERROR_COMPILE; 3151 default: return ERROR_RUNTIME; 3152 } 3153 } 3154 3155 static uc_vm_status_t 3156 uc_vm_execute_chunk(uc_vm_t *vm) 3157 { 3158 uc_callframe_t *frame = NULL; 3159 uc_chunk_t *chunk = NULL; 3160 size_t caller = vm->callframes.count - 1; 3161 uc_value_t *retval; 3162 uc_vm_insn_t insn; 3163 uint8_t *ip; 3164 3165 while (vm->callframes.count > caller) { 3166 frame = &vm->callframes.entries[vm->callframes.count - 1]; 3167 chunk = uc_vm_frame_chunk(frame); 3168 3169 if (!chunk) 3170 break; 3171 3172 if (vm->trace) { 3173 ip = frame->ip; 3174 insn = uc_vm_decode_insn(vm, frame, chunk); 3175 uc_dump_insn(vm, ip, insn); 3176 } 3177 else { 3178 insn = uc_vm_decode_insn(vm, frame, chunk); 3179 } 3180 3181 switch (insn) { 3182 case I_LOAD: 3183 case I_LOAD8: 3184 case I_LOAD16: 3185 case I_LOAD32: 3186 uc_vm_insn_load(vm, insn); 3187 break; 3188 3189 case I_LREXP: 3190 uc_vm_insn_load_regexp(vm, insn); 3191 break; 3192 3193 case I_LNULL: 3194 uc_vm_insn_load_null(vm, insn); 3195 break; 3196 3197 case I_LTRUE: 3198 case I_LFALSE: 3199 uc_vm_insn_load_bool(vm, insn); 3200 break; 3201 3202 case I_LTHIS: 3203 uc_vm_stack_push(vm, ucv_get(frame->ctx)); 3204 break; 3205 3206 case I_LVAR: 3207 uc_vm_insn_load_var(vm, insn); 3208 break; 3209 3210 case I_LVAL: 3211 uc_vm_insn_load_val(vm, insn); 3212 break; 3213 3214 case I_PVAL: 3215 uc_vm_insn_peek_val(vm, insn); 3216 break; 3217 3218 case I_LUPV: 3219 uc_vm_insn_load_upval(vm, insn); 3220 break; 3221 3222 case I_LLOC: 3223 uc_vm_insn_load_local(vm, insn); 3224 break; 3225 3226 case I_CLFN: 3227 case I_ARFN: 3228 uc_vm_insn_load_closure(vm, insn); 3229 break; 3230 3231 case I_NARR: 3232 uc_vm_insn_narr(vm, insn); 3233 break; 3234 3235 case I_PARR: 3236 uc_vm_insn_parr(vm, insn); 3237 break; 3238 3239 case I_MARR: 3240 uc_vm_insn_marr(vm, insn); 3241 break; 3242 3243 case I_NOBJ: 3244 uc_vm_insn_nobj(vm, insn); 3245 break; 3246 3247 case I_SOBJ: 3248 uc_vm_insn_sobj(vm, insn); 3249 break; 3250 3251 case I_MOBJ: 3252 uc_vm_insn_mobj(vm, insn); 3253 break; 3254 3255 case I_SVAR: 3256 uc_vm_insn_store_var(vm, insn); 3257 break; 3258 3259 case I_SVAL: 3260 uc_vm_insn_store_val(vm, insn); 3261 break; 3262 3263 case I_SUPV: 3264 uc_vm_insn_store_upval(vm, insn); 3265 break; 3266 3267 case I_SLOC: 3268 uc_vm_insn_store_local(vm, insn); 3269 break; 3270 3271 case I_UVAR: 3272 uc_vm_insn_update_var(vm, insn); 3273 break; 3274 3275 case I_UVAL: 3276 uc_vm_insn_update_val(vm, insn); 3277 break; 3278 3279 case I_UUPV: 3280 uc_vm_insn_update_upval(vm, insn); 3281 break; 3282 3283 case I_ULOC: 3284 uc_vm_insn_update_local(vm, insn); 3285 break; 3286 3287 case I_ADD: 3288 case I_SUB: 3289 case I_MUL: 3290 case I_DIV: 3291 case I_MOD: 3292 case I_EXP: 3293 uc_vm_insn_arith(vm, insn); 3294 break; 3295 3296 case I_PLUS: 3297 case I_MINUS: 3298 uc_vm_insn_plus_minus(vm, insn); 3299 break; 3300 3301 case I_LSHIFT: 3302 case I_RSHIFT: 3303 case I_BAND: 3304 case I_BXOR: 3305 case I_BOR: 3306 uc_vm_insn_bitop(vm, insn); 3307 break; 3308 3309 case I_COMPL: 3310 uc_vm_insn_complement(vm, insn); 3311 break; 3312 3313 case I_EQS: 3314 case I_NES: 3315 uc_vm_insn_equality(vm, insn); 3316 break; 3317 3318 case I_EQ: 3319 case I_NE: 3320 case I_LT: 3321 case I_LE: 3322 case I_GT: 3323 case I_GE: 3324 uc_vm_insn_rel(vm, insn); 3325 break; 3326 3327 case I_IN: 3328 uc_vm_insn_in(vm, insn); 3329 break; 3330 3331 case I_NOT: 3332 uc_vm_insn_not(vm, insn); 3333 break; 3334 3335 case I_JMP: 3336 uc_vm_insn_jmp(vm, insn); 3337 break; 3338 3339 case I_JMPZ: 3340 uc_vm_insn_jmpz(vm, insn); 3341 break; 3342 3343 case I_JMPNT: 3344 uc_vm_insn_jmpnt(vm, insn); 3345 break; 3346 3347 case I_NEXTK: 3348 case I_NEXTKV: 3349 uc_vm_insn_next(vm, insn); 3350 break; 3351 3352 case I_COPY: 3353 uc_vm_stack_push(vm, ucv_get(uc_vm_stack_peek(vm, vm->arg.u8))); 3354 break; 3355 3356 case I_POP: 3357 ucv_put(uc_vm_stack_pop(vm)); 3358 uc_vm_gc_step(vm); 3359 break; 3360 3361 case I_CUPV: 3362 uc_vm_insn_close_upval(vm, insn); 3363 break; 3364 3365 case I_CALL: 3366 uc_vm_insn_call(vm); 3367 3368 if (vm->callframes.count == 0) 3369 return uc_vm_exception_type_to_status(vm); 3370 3371 /* frame and chunk are re-derived from the (now callee) top callframe 3372 * at the top of the loop; nothing between here and there reads them. */ 3373 break; 3374 3375 case I_RETURN: 3376 retval = uc_vm_callframe_pop(vm); 3377 3378 uc_vm_stack_push(vm, retval); 3379 3380 if (vm->callframes.count == 0) 3381 return STATUS_OK; 3382 break; 3383 3384 case I_PRINT: 3385 uc_vm_insn_print(vm, insn); 3386 break; 3387 3388 case I_DELETE: 3389 uc_vm_insn_delete(vm, insn); 3390 break; 3391 3392 case I_IMPORT: 3393 uc_vm_insn_import(vm, insn); 3394 break; 3395 3396 case I_EXPORT: 3397 uc_vm_insn_export(vm, insn); 3398 break; 3399 3400 case I_DYNLOAD: 3401 uc_vm_insn_dynload(vm, insn); 3402 break; 3403 3404 default: 3405 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "unknown opcode %d", insn); 3406 break; 3407 } 3408 3409 exception: 3410 /* previous instruction raised exception */ 3411 if (vm->exception.type != EXCEPTION_NONE) { 3412 /* VM termination was requested */ 3413 if (vm->exception.type == EXCEPTION_EXIT) { 3414 uc_vm_reset_callframes(vm); 3415 3416 return STATUS_EXIT; 3417 } 3418 3419 /* If a debugger has armed the dedicated "break on uncaught 3420 * exception" system breakpoint and nothing between here and 3421 * this invocation's original call depth would actually handle 3422 * this exception, give it a chance to inspect the fully intact 3423 * stack *before* uc_vm_handle_exception()'s loop below starts 3424 * popping frames - once that happens, the original throwing 3425 * frame's locals and exact position are gone for good. */ 3426 if (!uc_vm_exception_would_be_caught(vm, caller)) { 3427 for (size_t i = 0; i < vm->breakpoints.count; i++) { 3428 uc_breakpoint_t *bk = vm->breakpoints.entries[i]; 3429 3430 if (bk != NULL && bk->ip == UC_BREAKPOINT_UNCAUGHT_EXCEPTION) { 3431 bk->cb(vm, bk); 3432 3433 /* "quit" was issued from within the breakpoint's 3434 * CLI session */ 3435 if (vm->exception.type == EXCEPTION_EXIT) { 3436 uc_vm_reset_callframes(vm); 3437 3438 return STATUS_EXIT; 3439 } 3440 3441 break; 3442 } 3443 } 3444 } 3445 3446 /* walk up callframes until something handles the exception or the original caller is reached */ 3447 while (!uc_vm_handle_exception(vm)) { 3448 /* no further callframe, report unhandled exception and terminate */ 3449 if (vm->callframes.count == 0) 3450 return ERROR_RUNTIME; 3451 3452 /* if VM returned into native function, don't bubble up */ 3453 if (!vm->callframes.entries[vm->callframes.count - 1].closure) 3454 return ERROR_RUNTIME; 3455 3456 /* no exception handler in current function, pop callframe */ 3457 ucv_put(uc_vm_callframe_pop(vm)); 3458 3459 /* do not bubble past original call depth */ 3460 if (vm->callframes.count <= caller) 3461 return ERROR_RUNTIME; 3462 } 3463 } 3464 3465 /* run handler for signal(s) delivered during previous instruction */ 3466 if (uc_vm_signal_dispatch(vm) != EXCEPTION_NONE) 3467 goto exception; 3468 3469 /* check for break request */ 3470 if (vm->break_requested) { 3471 vm->break_requested = false; 3472 return STATUS_BREAK; 3473 } 3474 } 3475 3476 return STATUS_OK; 3477 } 3478 3479 uc_vm_status_t 3480 uc_vm_execute(uc_vm_t *vm, uc_program_t *program, uc_value_t **retval) 3481 { 3482 uc_closure_t *closure = ucv_as_closure(uc_program_main(vm, program)); 3483 uc_function_t *fn = closure->function; 3484 uc_vm_status_t status; 3485 uc_callframe_t *frame; 3486 uc_stringbuf_t *buf; 3487 uc_value_t *val; 3488 3489 frame = uc_vector_push(&vm->callframes, { 3490 .closure = closure, 3491 .stackframe = 0, 3492 .ip = fn->chunk.entries, 3493 .strict = fn->strict 3494 }); 3495 3496 if (vm->trace) { 3497 buf = xprintbuf_new(); 3498 3499 uc_source_context_format(buf, uc_vm_frame_source(frame), 0, true); 3500 3501 fwrite(buf->buf, 1, printbuf_length(buf), stderr); 3502 printbuf_free(buf); 3503 3504 uc_vm_frame_dump(vm, frame); 3505 } 3506 3507 //uc_vm_stack_push(vm, closure->header.jso); 3508 uc_vm_stack_push(vm, NULL); 3509 3510 status = uc_vm_execute_chunk(vm); 3511 3512 switch (status) { 3513 case STATUS_OK: 3514 val = uc_vm_stack_pop(vm); 3515 3516 if (retval) 3517 *retval = val; 3518 else 3519 ucv_put(val); 3520 3521 break; 3522 3523 case STATUS_EXIT: 3524 if (retval) 3525 *retval = ucv_int64_new(vm->arg.s32); 3526 3527 break; 3528 3529 case STATUS_BREAK: 3530 /* Break requested - exit gracefully without error */ 3531 if (retval) 3532 *retval = NULL; 3533 3534 break; 3535 3536 default: 3537 if (vm->exhandler) 3538 vm->exhandler(vm, &vm->exception); 3539 3540 if (retval) 3541 *retval = NULL; 3542 3543 break; 3544 } 3545 3546 return status; 3547 } 3548 3549 uc_exception_type_t 3550 uc_vm_call(uc_vm_t *vm, bool mcall, size_t nargs) 3551 { 3552 uc_value_t *ctx = mcall ? ucv_get(uc_vm_stack_peek(vm, nargs + 1)) : NULL; 3553 uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, nargs)); 3554 3555 uc_vm_clear_exception(vm); 3556 3557 if (uc_vm_call_function(vm, ctx, fno, mcall, nargs & 0xffff, false)) { 3558 if (ucv_type(fno) != UC_CFUNCTION) 3559 uc_vm_execute_chunk(vm); 3560 } 3561 3562 return vm->exception.type; 3563 } 3564 3565 uc_value_t * 3566 uc_vm_scope_get(uc_vm_t *vm) 3567 { 3568 return vm->globals; 3569 } 3570 3571 void 3572 uc_vm_scope_set(uc_vm_t *vm, uc_value_t *ctx) 3573 { 3574 ucv_put(vm->globals); 3575 vm->globals = ctx; 3576 } 3577 3578 uc_value_t * 3579 uc_vm_invoke(uc_vm_t *vm, const char *fname, size_t nargs, ...) 3580 { 3581 uc_exception_type_t ex; 3582 uc_value_t *fno, *arg; 3583 va_list ap; 3584 size_t i; 3585 3586 fno = ucv_property_get(vm->globals, fname); 3587 3588 if (!ucv_is_callable(fno)) 3589 return NULL; 3590 3591 uc_vm_stack_push(vm, ucv_get(fno)); 3592 3593 va_start(ap, nargs); 3594 3595 for (i = 0; i < nargs; i++) { 3596 arg = va_arg(ap, uc_value_t *); 3597 uc_vm_stack_push(vm, ucv_get(arg)); 3598 } 3599 3600 va_end(ap); 3601 3602 ex = uc_vm_call(vm, false, nargs); 3603 3604 if (ex) { 3605 if (vm->exhandler) 3606 vm->exhandler(vm, &vm->exception); 3607 3608 return NULL; 3609 } 3610 3611 return uc_vm_stack_pop(vm); 3612 } 3613 3614 uc_exception_handler_t * 3615 uc_vm_exception_handler_get(uc_vm_t *vm) 3616 { 3617 return vm->exhandler; 3618 } 3619 3620 void 3621 uc_vm_exception_handler_set(uc_vm_t *vm, uc_exception_handler_t *exhandler) 3622 { 3623 vm->exhandler = exhandler; 3624 } 3625 3626 uint32_t 3627 uc_vm_trace_get(uc_vm_t *vm) 3628 { 3629 return vm->trace; 3630 } 3631 3632 void 3633 uc_vm_trace_set(uc_vm_t *vm, uint32_t level) 3634 { 3635 vm->trace = level; 3636 } 3637 3638 bool 3639 uc_vm_registry_exists(uc_vm_t *vm, const char *key) 3640 { 3641 bool exists; 3642 3643 ucv_object_get(vm->registry, key, &exists); 3644 3645 return exists; 3646 } 3647 3648 uc_value_t * 3649 uc_vm_registry_get(uc_vm_t *vm, const char *key) 3650 { 3651 return ucv_object_get(vm->registry, key, NULL); 3652 } 3653 3654 void 3655 uc_vm_registry_set(uc_vm_t *vm, const char *key, uc_value_t *value) 3656 { 3657 if (!vm->registry) 3658 vm->registry = ucv_object_new(vm); 3659 3660 ucv_object_add(vm->registry, key, value); 3661 } 3662 3663 bool 3664 uc_vm_registry_delete(uc_vm_t *vm, const char *key) 3665 { 3666 return ucv_object_delete(vm->registry, key); 3667 } 3668 3669 bool 3670 uc_vm_gc_start(uc_vm_t *vm, uint16_t interval) 3671 { 3672 bool changed = false; 3673 3674 if (vm->gc_interval != interval) { 3675 vm->gc_interval = interval; 3676 changed = true; 3677 } 3678 3679 if (!(vm->gc_flags & UC_GC_ENABLED)) { 3680 vm->gc_flags |= UC_GC_ENABLED; 3681 changed = true; 3682 } 3683 3684 return changed; 3685 } 3686 3687 bool 3688 uc_vm_gc_stop(uc_vm_t *vm) 3689 { 3690 if (!(vm->gc_flags & UC_GC_ENABLED)) 3691 return false; 3692 3693 vm->gc_flags &= ~UC_GC_ENABLED; 3694 3695 return true; 3696 } 3697 3698 void 3699 uc_vm_signal_raise(uc_vm_t *vm, int signo) 3700 { 3701 uint8_t signum = signo; 3702 3703 if (signo <= 0 || signo >= UC_SYSTEM_SIGNAL_COUNT) 3704 return; 3705 3706 vm->signal.raised[signo / 64] |= (1ull << (signo % 64)); 3707 3708 if (write(vm->signal.sigpipe[1], &signum, sizeof(signum)) == -1) {} 3709 } 3710 3711 int 3712 uc_vm_signal_notifyfd(uc_vm_t *vm) 3713 { 3714 return vm->signal.sigpipe[0]; 3715 } 3716 3717 bool 3718 uc_vm_break_requested(uc_vm_t *vm) 3719 { 3720 return vm->break_requested; 3721 } 3722 3723 void 3724 uc_vm_break_request(uc_vm_t *vm) 3725 { 3726 vm->break_requested = true; 3727 3728 if (vm->break_notifyfd[1] >= 0) { 3729 char c = 'B'; 3730 if (write(vm->break_notifyfd[1], &c, 1) == -1) {} 3731 } 3732 } 3733 3734 int 3735 uc_vm_break_notifyfd(uc_vm_t *vm) 3736 { 3737 return vm->break_notifyfd[0]; 3738 } 3739 3740 uc_vm_status_t 3741 uc_vm_resume(uc_vm_t *vm) 3742 { 3743 uc_vm_status_t status = uc_vm_execute_chunk(vm); 3744 3745 switch (status) { 3746 case STATUS_OK: 3747 case STATUS_EXIT: 3748 case STATUS_BREAK: 3749 break; 3750 3751 default: 3752 if (vm->exhandler) 3753 vm->exhandler(vm, &vm->exception); 3754 3755 break; 3756 } 3757 3758 return status; 3759 } 3760
This page was automatically generated by LXR 0.3.1. • OpenWrt