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