MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor vm call system for improved call mode handling

- add support for explicit this binding mode
- introduce call plan system with distinct execution paths
- improve closure and cfunc resolution logic

+268 -180
+211 -105
include/silver/engine.h
··· 442 442 return &frame->lp[slot_idx - param_count]; 443 443 } 444 444 445 - static inline ant_value_t sv_vm_call( 446 - sv_vm_t *vm, ant_t *js, ant_value_t func, 447 - ant_value_t this_val, ant_value_t *args, int argc, 448 - ant_value_t *out_this, bool is_construct_call 449 - ); 450 - 451 445 static inline void sv_vm_maybe_checkpoint_microtasks(ant_t *js) { 452 446 if (!js || js->microtasks_draining || js->vm_exec_depth != 0) return; 453 447 js_maybe_drain_microtasks(js); 454 448 } 455 449 456 450 typedef struct { 457 - ant_value_t this_val; 458 - ant_value_t super_val; 451 + ant_value_t this_val; 452 + ant_value_t super_val; 459 453 ant_value_t *args; 460 - int argc; 454 + int argc; 461 455 ant_value_t *alloc; 462 456 } sv_call_ctx_t; 463 457 464 - static inline ant_value_t sv_call_cfunc( 465 - ant_t *js, ant_value_t func, 466 - ant_value_t this_val, ant_value_t *args, int argc 467 - ) { 468 - js->this_val = this_val; 469 - return js_as_cfunc(func)(js, args, argc); 470 - } 458 + typedef enum { 459 + SV_CALL_MODE_NORMAL = 0, 460 + SV_CALL_MODE_EXPLICIT_THIS, 461 + SV_CALL_MODE_CONSTRUCT, 462 + } sv_call_mode_t; 463 + 464 + typedef enum { 465 + SV_CALL_EXEC_NATIVE = 0, 466 + SV_CALL_EXEC_PROXY_APPLY, 467 + SV_CALL_EXEC_PROXY_CONSTRUCT, 468 + SV_CALL_EXEC_DEFAULT_CTOR, 469 + SV_CALL_EXEC_CLOSURE, 470 + } sv_call_exec_kind_t; 471 + 472 + typedef struct { 473 + sv_call_exec_kind_t kind; 474 + ant_value_t func; 475 + sv_closure_t *closure; 476 + sv_call_ctx_t ctx; 477 + } sv_call_plan_t; 471 478 472 479 static inline ant_value_t *sv_prepend_bound_args( 473 480 sv_closure_t *closure, ant_value_t *args, int argc, int *out_total 474 481 ) { 475 482 int total = closure->bound_argc + argc; 476 483 ant_value_t *combined = malloc(sizeof(ant_value_t) * (size_t)total); 484 + 477 485 if (!combined) { *out_total = argc; return NULL; } 478 486 memcpy(combined, closure->bound_argv, sizeof(ant_value_t) * (size_t)closure->bound_argc); 479 487 memcpy(combined + closure->bound_argc, args, sizeof(ant_value_t) * (size_t)argc); 488 + 480 489 *out_total = total; 481 490 return combined; 482 491 } 483 492 484 - static inline ant_value_t sv_call_resolve_bound(ant_t *js, sv_closure_t *closure, sv_call_ctx_t *ctx) { 493 + static inline bool sv_call_mode_is_construct(sv_call_mode_t mode) { 494 + return mode == SV_CALL_MODE_CONSTRUCT; 495 + } 496 + 497 + static inline ant_value_t sv_call_normalize_this(ant_t *js, ant_value_t this_val, sv_call_mode_t mode) { 498 + if (mode == SV_CALL_MODE_NORMAL && sv_is_nullish_this(this_val)) return js->global; 499 + return this_val; 500 + } 501 + 502 + static inline ant_value_t sv_call_resolve_bound( 503 + ant_t *js, sv_closure_t *closure, 504 + sv_call_ctx_t *ctx, sv_call_mode_t mode 505 + ) { 485 506 uint32_t flags = closure->call_flags; 486 507 487 508 if (flags & SV_CALL_IS_ARROW) ctx->this_val = closure->bound_this; 488 - else if (vtype(closure->bound_this) != T_UNDEF) ctx->this_val = closure->bound_this; 509 + else if (!sv_call_mode_is_construct(mode) && vtype(closure->bound_this) != T_UNDEF) 510 + ctx->this_val = closure->bound_this; 489 511 490 512 if ((flags & SV_CALL_HAS_BOUND_ARGS) && closure->bound_argc > 0) { 491 513 int total; ··· 497 519 } 498 520 499 521 if (flags & SV_CALL_HAS_SUPER) ctx->super_val = closure->super_val; 500 - 501 522 return js_mkundef(); 502 523 } 503 524 ··· 508 529 static inline ant_value_t sv_call_default_ctor( 509 530 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 510 531 sv_call_ctx_t *ctx, ant_value_t *out_this 532 + ); 533 + 534 + static inline ant_value_t sv_call_resolve_closure( 535 + sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 536 + ant_value_t callee_func, sv_call_ctx_t *ctx, ant_value_t *out_this 537 + ); 538 + 539 + static inline ant_value_t sv_prepare_call( 540 + sv_vm_t *vm, ant_t *js, ant_value_t func, 541 + ant_value_t this_val, ant_value_t *args, int argc, 542 + ant_value_t *out_this, sv_call_mode_t mode, sv_call_plan_t *plan 511 543 ) { 512 - if (vtype(js->new_target) == T_UNDEF) { 513 - sv_call_cleanup(js, ctx); 514 - return js_mkerr_typed( 515 - js, JS_ERR_TYPE, 516 - "Class constructor cannot be invoked without 'new'" 517 - ); 544 + bool is_construct_call = sv_call_mode_is_construct(mode); 545 + 546 + plan->kind = SV_CALL_EXEC_NATIVE; 547 + plan->func = func; 548 + plan->closure = NULL; 549 + 550 + plan->ctx = (sv_call_ctx_t){ 551 + .this_val = this_val, 552 + .super_val = js_mkundef(), 553 + .args = args, 554 + .argc = argc, 555 + .alloc = NULL, 556 + }; 557 + 558 + if (!is_construct_call) js->new_target = js_mkundef(); 559 + if (out_this) *out_this = this_val; 560 + 561 + if (is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 562 + plan->kind = SV_CALL_EXEC_PROXY_CONSTRUCT; 563 + return js_mkundef(); 564 + } 565 + 566 + if (is_construct_call && !js_is_constructor(js, func)) 567 + return js_mkerr_typed(js, JS_ERR_TYPE, "not a constructor"); 568 + 569 + if (!is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 570 + plan->kind = SV_CALL_EXEC_PROXY_APPLY; 571 + return js_mkundef(); 572 + } 573 + 574 + if (vtype(func) == T_CFUNC || vtype(func) == T_FFI) { 575 + plan->ctx.this_val = sv_call_normalize_this(js, this_val, mode); 576 + if (out_this) *out_this = plan->ctx.this_val; 577 + return js_mkundef(); 518 578 } 519 579 580 + if (vtype(func) != T_FUNC) 581 + return js_mkerr_typed(js, JS_ERR_TYPE, "%s is not a function", typestr(vtype(func))); 582 + 583 + sv_closure_t *closure = js_func_closure(func); 584 + plan->closure = closure; 585 + 586 + ant_value_t err = sv_call_resolve_bound(js, closure, &plan->ctx, mode); 587 + if (is_err(err)) return err; 588 + 589 + if (is_construct_call) plan->ctx.this_val = this_val; 590 + if (out_this) *out_this = plan->ctx.this_val; 591 + 592 + if (closure->call_flags & SV_CALL_IS_DEFAULT_CTOR) { 593 + plan->kind = SV_CALL_EXEC_DEFAULT_CTOR; 594 + return js_mkundef(); 595 + } 596 + 597 + if (closure->func != NULL) { 598 + plan->kind = SV_CALL_EXEC_CLOSURE; 599 + return js_mkundef(); 600 + } 601 + 602 + return js_mkundef(); 603 + } 604 + 605 + static inline ant_value_t sv_execute_call_plan( 606 + sv_vm_t *vm, ant_t *js, sv_call_plan_t *plan, ant_value_t *out_this 607 + ) { 608 + switch (plan->kind) { 609 + case SV_CALL_EXEC_PROXY_APPLY: return js_proxy_apply( 610 + js, plan->func, plan->ctx.this_val, plan->ctx.args, plan->ctx.argc 611 + ); 612 + 613 + case SV_CALL_EXEC_PROXY_CONSTRUCT: return js_proxy_construct( 614 + js, plan->func, plan->ctx.args, plan->ctx.argc, sv_vm_get_new_target(vm, js) 615 + ); 616 + 617 + case SV_CALL_EXEC_DEFAULT_CTOR: return sv_call_default_ctor( 618 + vm, js, plan->closure, &plan->ctx, out_this 619 + ); 620 + 621 + case SV_CALL_EXEC_CLOSURE: return sv_call_resolve_closure( 622 + vm, js, plan->closure, plan->func, &plan->ctx, out_this 623 + ); 624 + 625 + case SV_CALL_EXEC_NATIVE: { 626 + ant_value_t result = sv_call_native( 627 + js, plan->func, plan->ctx.this_val, plan->ctx.args, plan->ctx.argc 628 + ); 629 + sv_call_cleanup(js, &plan->ctx); 630 + return result; 631 + }} 632 + 633 + return js_mkerr(js, "invalid call plan"); 634 + } 635 + 636 + static inline bool sv_check_c_stack_overflow(ant_t *js) { 637 + volatile char marker; 638 + if (js->cstk.limit == 0 || js->cstk.base == NULL) return false; 639 + 640 + uintptr_t base = (uintptr_t)js->cstk.base; 641 + uintptr_t curr = (uintptr_t)▮ 642 + 643 + size_t used = (base > curr) ? (base - curr) : (curr - base); 644 + return used > js->cstk.limit; 645 + } 646 + 647 + static inline ant_value_t sv_vm_call( 648 + sv_vm_t *vm, ant_t *js, ant_value_t func, 649 + ant_value_t this_val, ant_value_t *args, int argc, 650 + ant_value_t *out_this, bool is_construct_call 651 + ) { 652 + if (sv_check_c_stack_overflow(js)) 653 + return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 654 + 655 + sv_call_mode_t mode = is_construct_call 656 + ? SV_CALL_MODE_CONSTRUCT 657 + : SV_CALL_MODE_NORMAL; 658 + 659 + sv_call_plan_t plan; 660 + ant_value_t err = sv_prepare_call( 661 + vm, js, func, this_val, args, argc, 662 + out_this, mode, &plan 663 + ); 664 + 665 + if (is_err(err)) return err; 666 + ant_value_t result = sv_execute_call_plan(vm, js, &plan, out_this); 667 + sv_vm_maybe_checkpoint_microtasks(js); 668 + 669 + return result; 670 + } 671 + 672 + static inline ant_value_t sv_vm_call_explicit_this( 673 + sv_vm_t *vm, ant_t *js, ant_value_t func, 674 + ant_value_t this_val, ant_value_t *args, int argc 675 + ) { 676 + if (sv_check_c_stack_overflow(js)) 677 + return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 678 + 679 + sv_call_plan_t plan; 680 + ant_value_t err = sv_prepare_call( 681 + vm, js, func, this_val, args, argc, NULL, 682 + SV_CALL_MODE_EXPLICIT_THIS, &plan 683 + ); 684 + 685 + if (is_err(err)) return err; 686 + ant_value_t result = sv_execute_call_plan(vm, js, &plan, NULL); 687 + sv_vm_maybe_checkpoint_microtasks(js); 688 + 689 + return result; 690 + } 691 + 692 + static inline ant_value_t sv_call_default_ctor( 693 + sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 694 + sv_call_ctx_t *ctx, ant_value_t *out_this 695 + ) { 696 + if (vtype(js->new_target) == T_UNDEF) { 697 + sv_call_cleanup(js, ctx); 698 + return js_mkerr_typed( 699 + js, JS_ERR_TYPE, 700 + "Class constructor cannot be invoked without 'new'" 701 + );} 702 + 520 703 ant_value_t super_ctor = closure->super_val; 521 704 uint8_t st = vtype(super_ctor); 705 + 522 706 if (st == T_FUNC || st == T_CFUNC) { 523 707 ant_value_t super_this = ctx->this_val; 524 708 ant_value_t result = sv_vm_call( 525 709 vm, js, super_ctor, ctx->this_val, 526 710 ctx->args, ctx->argc, &super_this, true 527 711 ); 712 + 528 713 if (out_this) *out_this = super_this; 529 714 sv_call_cleanup(js, ctx); 715 + 530 716 return result; 531 717 } 532 718 ··· 823 1009 } 824 1010 #endif 825 1011 return sv_call_closure(vm, js, closure, callee_func, ctx, out_this); 826 - } 827 - 828 - static inline bool sv_check_c_stack_overflow(ant_t *js) { 829 - volatile char marker; 830 - if (js->cstk.limit == 0 || js->cstk.base == NULL) return false; 831 - uintptr_t base = (uintptr_t)js->cstk.base; 832 - uintptr_t curr = (uintptr_t)▮ 833 - size_t used = (base > curr) ? (base - curr) : (curr - base); 834 - return used > js->cstk.limit; 835 - } 836 - 837 - static inline ant_value_t sv_vm_call( 838 - sv_vm_t *vm, ant_t *js, ant_value_t func, 839 - ant_value_t this_val, ant_value_t *args, int argc, 840 - ant_value_t *out_this, bool is_construct_call 841 - ) { 842 - if (sv_check_c_stack_overflow(js)) 843 - return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 844 - 845 - if (!is_construct_call) js->new_target = js_mkundef(); 846 - if (out_this) *out_this = this_val; 847 - 848 - if (is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 849 - ant_value_t result = js_proxy_construct(js, func, args, argc, sv_vm_get_new_target(vm, js)); 850 - sv_vm_maybe_checkpoint_microtasks(js); 851 - return result; 852 - } 853 - 854 - if (is_construct_call && !js_is_constructor(js, func)) 855 - return js_mkerr_typed(js, JS_ERR_TYPE, "not a constructor"); 856 - 857 - if (!is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 858 - ant_value_t result = js_proxy_apply(js, func, this_val, args, argc); 859 - sv_vm_maybe_checkpoint_microtasks(js); 860 - return result; 861 - } 862 - 863 - if (vtype(func) == T_CFUNC) { 864 - ant_value_t cfunc_this = sv_is_nullish_this(this_val) ? js->global : this_val; 865 - ant_value_t result = sv_call_cfunc(js, func, cfunc_this, args, argc); 866 - sv_vm_maybe_checkpoint_microtasks(js); 867 - return result; 868 - } 869 - 870 - if (vtype(func) != T_FUNC) { 871 - ant_value_t result = sv_call_native(js, func, this_val, args, argc); 872 - sv_vm_maybe_checkpoint_microtasks(js); 873 - return result; 874 - } 875 - 876 - sv_closure_t *closure = js_func_closure(func); 877 - 878 - sv_call_ctx_t ctx = { 879 - .this_val = this_val, .super_val = js_mkundef(), 880 - .args = args, .argc = argc, .alloc = NULL, 881 - }; 882 - 883 - ant_value_t err = sv_call_resolve_bound(js, closure, &ctx); 884 - if (is_err(err)) return err; 885 - 886 - if (is_construct_call) ctx.this_val = this_val; 887 - if (out_this) *out_this = ctx.this_val; 888 - 889 - if (closure->call_flags & SV_CALL_IS_DEFAULT_CTOR) { 890 - ant_value_t result = sv_call_default_ctor(vm, js, closure, &ctx, out_this); 891 - sv_vm_maybe_checkpoint_microtasks(js); 892 - return result; 893 - } 894 - 895 - if (closure->func != NULL) { 896 - ant_value_t result = sv_call_resolve_closure(vm, js, closure, func, &ctx, out_this); 897 - sv_vm_maybe_checkpoint_microtasks(js); 898 - return result; 899 - } 900 - 901 - ant_value_t result = sv_call_native(js, func, ctx.this_val, ctx.args, ctx.argc); 902 - sv_call_cleanup(js, &ctx); 903 - sv_vm_maybe_checkpoint_microtasks(js); 904 - 905 - return result; 906 1012 } 907 1013 908 1014 #endif
+2
include/types.h
··· 26 26 typedef uint64_t ant_value_t; 27 27 28 28 typedef ant_value_t (*ant_cfunc_t) (ant_t *, ant_value_t *, int); 29 + 30 + #define ant_bind_t ant_value_t func, ant_value_t this_val 29 31 #define ant_params_t ant_t *js, ant_value_t *args, int nargs 30 32 31 33 #endif
+45 -69
src/ant.c
··· 2830 2830 2831 2831 ant_value_t js_instance_proto_from_new_target(ant_t *js, ant_value_t fallback_proto) { 2832 2832 ant_value_t instance_proto = js_mkundef(); 2833 - 2833 + 2834 2834 if (vtype(js->new_target) == T_FUNC || vtype(js->new_target) == T_CFUNC) { 2835 2835 ant_value_t nt_obj = js_as_obj(js->new_target); 2836 2836 ant_value_t nt_proto = lkp_interned_val(js, nt_obj, INTERN_PROTOTYPE); 2837 2837 if (is_object_type(nt_proto)) instance_proto = nt_proto; 2838 2838 } 2839 + 2840 + if (!is_object_type(instance_proto) && is_object_type(fallback_proto)) 2841 + instance_proto = fallback_proto; 2839 2842 2840 - if (!is_object_type(instance_proto) && is_object_type(fallback_proto)) { 2841 - instance_proto = fallback_proto; 2842 - } return instance_proto; 2843 + return instance_proto; 2843 2844 } 2844 2845 2845 2846 bool proto_chain_contains(ant_t *js, ant_value_t obj, ant_value_t proto_target) { ··· 4750 4751 } 4751 4752 4752 4753 static ant_value_t builtin_function_empty(ant_t *js, ant_value_t *args, int nargs) { 4753 - (void)js; (void)args; (void)nargs; 4754 4754 return js_mkundef(); 4755 4755 } 4756 4756 4757 - static bool function_uses_native_call(ant_value_t func) { 4758 - if (vtype(func) == T_CFUNC) return true; 4759 - if (vtype(func) != T_FUNC) return false; 4760 - 4761 - ant_value_t func_obj = js_func_obj(func); 4762 - return vtype(get_slot(func_obj, SLOT_CFUNC)) == T_CFUNC; 4763 - } 4764 - 4765 - static ant_value_t function_call_dispatch( 4766 - ant_t *js, 4767 - ant_value_t func, 4768 - ant_value_t this_arg, 4769 - ant_value_t *call_args, 4770 - int call_nargs 4771 - ) { 4772 - if (function_uses_native_call(func)) return sv_call_native(js, func, this_arg, call_args, call_nargs); 4773 - return sv_vm_call(js->vm, js, func, this_arg, call_args, call_nargs, NULL, false); 4774 - } 4775 - 4776 4757 static ant_value_t builtin_function_call(ant_t *js, ant_value_t *args, int nargs) { 4777 4758 ant_value_t func = js->this_val; 4778 4759 if (vtype(func) != T_FUNC && vtype(func) != T_CFUNC) { ··· 4785 4766 int call_nargs = (nargs > 1) ? nargs - 1 : 0; 4786 4767 if (call_nargs > 0) call_args = &args[1]; 4787 4768 4788 - return function_call_dispatch(js, func, this_arg, call_args, call_nargs); 4769 + return sv_vm_call_explicit_this(js->vm, js, func, this_arg, call_args, call_nargs); 4789 4770 } 4790 4771 4791 4772 static int extract_array_args(ant_t *js, ant_value_t arr, ant_value_t **out_args) { ··· 4908 4889 } else if (t != T_UNDEF && t != T_NULL) {} 4909 4890 } 4910 4891 4911 - ant_value_t result = function_call_dispatch(js, func, this_arg, call_args, call_nargs); 4892 + ant_value_t result = sv_vm_call_explicit_this(js->vm, js, func, this_arg, call_args, call_nargs); 4912 4893 if (call_args) free(call_args); 4913 4894 4914 4895 return result; ··· 13383 13364 return js_eval_bytecode_mode(js, buf, len, SV_COMPILE_REPL, false); 13384 13365 } 13385 13366 13367 + ant_value_t inline sv_call_cfunc(ant_params_t, ant_bind_t) { 13368 + ant_value_t saved_this = js->this_val; 13369 + js->this_val = this_val; 13370 + ant_value_t res = js_as_cfunc(func)(js, args, nargs); 13371 + js->this_val = saved_this; 13372 + return res; 13373 + } 13374 + 13375 + ant_value_t inline sv_call_slot_cfunc(ant_params_t, ant_bind_t, ant_value_t cfunc_slot) { 13376 + ant_value_t saved_func = js->current_func; 13377 + ant_value_t saved_this = js->this_val; 13378 + js->current_func = func; 13379 + js->this_val = this_val; 13380 + ant_value_t res = js_as_cfunc(cfunc_slot)(js, args, nargs); 13381 + js->current_func = saved_func; 13382 + js->this_val = saved_this; 13383 + return res; 13384 + } 13385 + 13386 + 13387 + ant_value_t inline sv_call_object_builtin(ant_params_t, ant_value_t this_val) { 13388 + ant_value_t saved_this = js->this_val; 13389 + js->this_val = this_val; 13390 + ant_value_t res = builtin_Object(js, args, nargs); 13391 + js->this_val = saved_this; 13392 + return res; 13393 + } 13394 + 13386 13395 ant_value_t sv_call_native( 13387 13396 ant_t *js, ant_value_t func, ant_value_t this_val, 13388 13397 ant_value_t *args, int nargs 13389 13398 ) { 13390 - if (vtype(func) == T_FFI) 13391 - return ffi_call_by_index(js, (unsigned int)vdata(func), args, nargs); 13392 - 13393 - if (vtype(func) == T_CFUNC) { 13394 - ant_value_t saved_this = js->this_val; 13395 - js->this_val = this_val; 13396 - ant_value_t (*fn)(ant_t *, ant_value_t *, int) = (ant_value_t(*)(ant_t *, ant_value_t *, int))vdata(func); 13397 - ant_value_t res = fn(js, args, nargs); 13398 - js->this_val = saved_this; 13399 - return res; 13400 - } 13401 - 13399 + if (vtype(func) == T_CFUNC) return sv_call_cfunc(js, args, nargs, func, this_val); 13400 + if (vtype(func) == T_FFI) return ffi_call_by_index(js, (unsigned int)vdata(func), args, nargs); 13401 + 13402 13402 if (vtype(func) == T_FUNC) { 13403 - sv_closure_t *closure = js_func_closure(func); 13404 - ant_value_t func_obj = closure->func_obj; 13405 - 13403 + ant_value_t func_obj = js_func_obj(func); 13406 13404 ant_value_t cfunc_slot = get_slot(func_obj, SLOT_CFUNC); 13407 - if (vtype(cfunc_slot) == T_CFUNC) { 13408 - ant_value_t resolve_this = (vtype(closure->bound_this) != T_UNDEF) ? closure->bound_this : this_val; 13409 - int final_nargs = nargs; 13410 - ant_value_t *final_args = args; 13411 - ant_value_t *combined = NULL; 13412 - if ((closure->call_flags & SV_CALL_HAS_BOUND_ARGS) && closure->bound_argc > 0) { 13413 - combined = sv_prepend_bound_args(closure, args, nargs, &final_nargs); 13414 - if (combined) final_args = combined; 13415 - } 13416 - ant_value_t saved_func = js->current_func; 13417 - ant_value_t saved_this = js->this_val; 13418 - js->current_func = func; 13419 - js->this_val = resolve_this; 13420 - ant_value_t (*fn)(ant_t *, ant_value_t *, int) = (ant_value_t(*)(ant_t *, ant_value_t *, int))vdata(cfunc_slot); 13421 - ant_value_t res = fn(js, final_args, final_nargs); 13422 - js->current_func = saved_func; 13423 - js->this_val = saved_this; 13424 - if (combined) free(combined); 13425 - return res; 13426 - } 13427 - 13405 + 13406 + if (vtype(cfunc_slot) == T_CFUNC) 13407 + return sv_call_slot_cfunc(js, args, nargs, func, this_val, cfunc_slot); 13408 + 13428 13409 ant_value_t builtin_slot = get_slot(func_obj, SLOT_BUILTIN); 13429 - if (vtype(builtin_slot) == T_NUM && (int)tod(builtin_slot) == BUILTIN_OBJECT) { 13430 - ant_value_t saved_this = js->this_val; 13431 - js->this_val = this_val; 13432 - ant_value_t res = builtin_Object(js, args, nargs); 13433 - js->this_val = saved_this; 13434 - return res; 13435 - } 13410 + if (vtype(builtin_slot) == T_NUM && (int)tod(builtin_slot) == BUILTIN_OBJECT) 13411 + return sv_call_object_builtin(js, args, nargs, this_val); 13436 13412 } 13437 13413 13438 13414 return js_mkerr_typed(js, JS_ERR_TYPE, "%s is not a function", typestr(vtype(func)));
+10 -6
src/silver/engine.c
··· 831 831 } 832 832 call_fallback:; 833 833 frame->ip = ip; 834 + ant_value_t super_this_c = call_this; 834 835 ant_value_t call_result = sv_vm_call( 835 - vm, js, call_func, call_this, call_args, call_argc, NULL, false); 836 + vm, js, call_func, call_this, call_args, call_argc, 837 + is_super_call ? &super_this_c : NULL, is_super_call); 836 838 vm->sp -= call_argc + 1; 837 839 if (is_err(call_result)) { sv_err = call_result; goto sv_throw; } 838 - if (is_super_call && is_object_type(call_result)) 839 - frame->this = call_result; 840 + if (is_super_call) 841 + frame->this = is_object_type(call_result) ? call_result : super_this_c; 840 842 vm->stack[vm->sp++] = call_result; 841 843 NEXT(3); 842 844 } ··· 955 957 call_method_fallback:; 956 958 frame->ip = ip; 957 959 if (is_super_call) js->new_target = frame->new_target; 960 + ant_value_t super_this_cm = call_this; 958 961 ant_value_t call_result = sv_vm_call( 959 - vm, js, call_func, call_this, call_args, call_argc, NULL, is_super_call); 962 + vm, js, call_func, call_this, call_args, call_argc, 963 + is_super_call ? &super_this_cm : NULL, is_super_call); 960 964 vm->sp -= call_argc + 2; 961 965 if (is_err(call_result)) { sv_err = call_result; goto sv_throw; } 962 - if (is_super_call && is_object_type(call_result)) 963 - frame->this = call_result; 966 + if (is_super_call) 967 + frame->this = is_object_type(call_result) ? call_result : super_this_cm; 964 968 vm->stack[vm->sp++] = call_result; 965 969 NEXT(3); 966 970 }