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.

at type-hints-typescript 1147 lines 32 kB view raw
1#ifndef SILVER_ENGINE_H 2#define SILVER_ENGINE_H 3 4#include "silver/vm.h" 5#include "internal.h" 6#include "runtime.h" 7#include "errors.h" 8#include "gc/objects.h" 9#include "modules/timer.h" 10 11#include <stdbool.h> 12#include <stdint.h> 13#include <stdlib.h> 14#include <string.h> 15#include <stdio.h> 16 17typedef enum { 18#define OP_DEF(name, size, n_pop, n_push, f) OP_##name, 19#include "silver/opcode.h" 20 OP__COUNT 21} sv_op_t; 22 23static const uint8_t sv_op_size[OP__COUNT] = { 24#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = (size), 25#include "silver/opcode.h" 26}; 27 28typedef struct { 29 const char *str; 30 uint32_t len; 31} sv_atom_t; 32 33typedef struct { 34 uint16_t index; 35 bool is_local; 36 bool is_const; 37} sv_upval_desc_t; 38 39typedef struct { 40 uint32_t bc_offset; 41 uint32_t line; 42 uint32_t col; 43 uint32_t src_off; 44 uint32_t src_end; 45} sv_srcpos_t; 46 47typedef enum { 48 SV_TI_UNKNOWN = 0, 49 SV_TI_NUM, 50 SV_TI_STR, 51 SV_TI_ARR, 52 SV_TI_OBJ, 53 SV_TI_BOOL, 54 SV_TI_NULL, 55 SV_TI_UNDEF, 56} sv_local_type_t; 57 58typedef struct { 59 uint8_t type; 60} sv_type_info_t; 61 62typedef struct { 63 ant_shape_t *cached_shape; 64 ant_object_t *cached_holder; 65 uint32_t cached_index; 66 uint32_t epoch; 67 uintptr_t cached_aux; 68 ant_shape_t *add_from_shape; 69 ant_shape_t *add_to_shape; 70 uint32_t add_slot; 71 uint32_t add_epoch; 72 bool cached_is_own; 73} sv_ic_entry_t; 74 75typedef struct { 76 uint32_t bc_off; 77 ant_shape_t *shared_shape; 78} sv_obj_site_cache_t; 79 80#define SV_GF_IC_AUX_WARMUP_MASK ((uintptr_t)0xFFu) 81#define SV_GF_IC_AUX_MISS_MASK ((uintptr_t)0xFF00u) 82#define SV_GF_IC_AUX_ACTIVE_BIT ((uintptr_t)0x10000u) 83#define SV_GF_IC_AUX_MISS_SHIFT 8u 84 85#define SV_GF_IC_WARMUP_ENABLE 16u 86#define SV_GF_IC_MISS_DISABLE 4u 87 88static inline uint8_t sv_gf_ic_warmup(uintptr_t aux) { 89 return (uint8_t)(aux & SV_GF_IC_AUX_WARMUP_MASK); 90} 91 92static inline uint8_t sv_gf_ic_miss_streak(uintptr_t aux) { 93 return (uint8_t)((aux & SV_GF_IC_AUX_MISS_MASK) >> SV_GF_IC_AUX_MISS_SHIFT); 94} 95 96static inline bool sv_gf_ic_active(uintptr_t aux) { 97 return (aux & SV_GF_IC_AUX_ACTIVE_BIT) != 0; 98} 99 100static inline uintptr_t sv_gf_ic_pack_aux(uint8_t warmup, uint8_t miss_streak, bool active) { 101 uintptr_t aux = ((uintptr_t)warmup & SV_GF_IC_AUX_WARMUP_MASK) | 102 ((uintptr_t)miss_streak << SV_GF_IC_AUX_MISS_SHIFT); 103 if (active) aux |= SV_GF_IC_AUX_ACTIVE_BIT; 104 return aux; 105} 106 107bool sv_lookup_srcpos(sv_func_t *func, int bc_offset, uint32_t *line, uint32_t *col); 108bool sv_lookup_srcspan(sv_func_t *func, int bc_offset, uint32_t *src_off, uint32_t *src_end); 109 110#ifdef ANT_JIT 111typedef struct { 112 uint16_t bc_off; 113 uint8_t miss_count; 114 uint8_t disabled; 115 sv_func_t *target; 116} sv_call_target_fb_t; 117#endif 118 119struct sv_func { 120 uint8_t *code; 121 int code_len; 122 123 ant_value_t *constants; 124 int const_count; 125 126 struct sv_func **child_funcs; 127 int child_func_count; 128 129 uint32_t *gc_const_slots; 130 int gc_const_slot_count; 131 132 sv_atom_t *atoms; 133 int atom_count; 134 135 sv_ic_entry_t *ic_slots; 136 uint16_t ic_count; 137 138 sv_obj_site_cache_t *obj_sites; 139 uint16_t obj_site_count; 140 141 sv_upval_desc_t *upval_descs; 142 int max_locals; 143 int max_stack; 144 145 sv_type_info_t *local_types; 146 int local_type_count; 147 sv_type_info_t *param_hints; 148 int param_hint_count; 149 uint8_t return_hint; 150 151 int param_count; 152 int upvalue_count; 153 154 bool is_strict; 155 bool is_arrow; 156 bool is_async; 157 bool has_await; 158 bool is_generator; 159 bool is_method; 160 bool is_static; 161 bool is_tla; 162 uint64_t gc_epoch; 163 164 const char *name; 165 const char *filename; 166 167 sv_srcpos_t *srcpos; 168 int srcpos_count; 169 int source_line; 170 171 const char *source; 172 int source_len; 173 int source_start; 174 int source_end; 175 176#ifdef ANT_JIT 177 void *jit_code; 178 179 uint32_t call_count; 180 uint32_t back_edge_count; 181 182 bool jit_compile_failed; 183 bool jit_compiling; 184 uint32_t tfb_version; 185 uint32_t jit_compiled_tfb_ver; 186 uint8_t *type_feedback; 187 uint8_t *local_type_feedback; 188 uint8_t *param_type_feedback; 189 uint64_t ctor_prop_samples; 190 uint64_t ctor_prop_hist[17]; 191 uint8_t ctor_inobj_limit; 192 uint8_t ctor_inobj_frozen; 193 194 sv_call_target_fb_t *call_target_fb; 195 uint8_t call_target_fb_count; 196#endif 197}; 198 199typedef enum { 200 SV_COMPLETION_NONE = 0, 201 SV_COMPLETION_THROW = 1, 202 SV_COMPLETION_RETURN = 2, 203} sv_completion_kind_t; 204 205typedef struct { 206 sv_completion_kind_t kind; 207 ant_value_t value; 208} sv_completion_t; 209 210typedef enum { 211 SV_RESUME_NEXT = 0, 212 SV_RESUME_THROW = 1, 213 SV_RESUME_RETURN = 2, 214} sv_resume_kind_t; 215 216typedef struct 217 sv_upvalue sv_upvalue_t; 218 219typedef struct sv_frame { 220 uint8_t *ip; 221 ant_value_t *bp; 222 ant_value_t *lp; 223 224 sv_func_t *func; 225 ant_value_t callee; 226 ant_value_t this; 227 ant_value_t new_target; 228 ant_value_t super_val; 229 230 int prev_sp; 231 int handler_base; 232 int handler_top; 233 int argc; 234 235 sv_completion_t completion; 236 sv_upvalue_t **upvalues; 237 int upvalue_count; 238 239 ant_value_t with_obj; 240 ant_value_t arguments_obj; 241} sv_frame_t; 242 243typedef enum { 244 SV_HANDLER_TRY = 1, 245 SV_HANDLER_FINALLY = 2, 246} sv_handler_kind_t; 247 248typedef struct { 249 uint8_t *ip; 250 int saved_sp; 251 uint8_t kind; 252} sv_handler_t; 253 254struct sv_upvalue { 255 ant_value_t *location; 256 ant_value_t closed; 257 struct sv_upvalue *next; 258 uint64_t gc_epoch; 259}; 260 261static inline sv_upvalue_t *js_upvalue_alloc(void) { 262 return (sv_upvalue_t *)fixed_arena_alloc(&rt->js->upvalue_arena); 263} 264 265bool sv_slot_has_open_upvalue(sv_vm_t *vm, ant_value_t *slot); 266 267#define SV_CALL_HAS_BOUND_ARGS (1u << 0) 268#define SV_CALL_HAS_SUPER (1u << 1) 269#define SV_CALL_IS_ARROW (1u << 2) 270#define SV_CALL_IS_DEFAULT_CTOR (1u << 3) 271#define SV_CALL_BORROWED_UPVALS (1u << 4) 272 273typedef struct sv_closure { 274 uint32_t call_flags; 275 int bound_argc; 276 sv_func_t *func; 277 278 sv_upvalue_t **upvalues; 279 ant_value_t bound_this; 280 ant_value_t *bound_argv; 281 ant_value_t bound_args; 282 ant_value_t super_val; 283 ant_value_t func_obj; 284 285 uint64_t gc_epoch; 286} sv_closure_t; 287 288static inline sv_closure_t *js_closure_alloc(ant_t *js) { 289 sv_closure_t *c = (sv_closure_t *)fixed_arena_alloc(&js->closure_arena); 290 if (c) c->gc_epoch = gc_get_epoch(); 291 return c; 292} 293 294static inline sv_closure_t *js_func_closure(ant_value_t func) { 295 return (sv_closure_t *)(uintptr_t)vdata(func); 296} 297 298static inline ant_value_t js_func_obj(ant_value_t func) { 299 return js_func_closure(func)->func_obj; 300} 301 302static inline ant_value_t js_as_obj(ant_value_t v) { 303 uint8_t t = vtype(v); 304 if (t == T_OBJ) return v; 305 if (t == T_FUNC) return js_func_obj(v); 306 return mkval(T_OBJ, vdata(v)); 307} 308 309ant_value_t sv_execute_closure_entry( 310 sv_vm_t *vm,sv_closure_t *closure, 311 ant_value_t callee_func, ant_value_t super_val, 312 ant_value_t this_val, ant_value_t *args, 313 int argc, ant_value_t *out_this 314); 315 316#ifdef ANT_JIT 317typedef struct { 318 bool active; 319 int bc_offset; 320 ant_value_t *locals; 321 int n_locals; 322 ant_value_t *lp; 323} sv_jit_osr_t; 324#endif 325 326#define SV_TRY_MAX 64 327#define SV_TDZ T_EMPTY 328#define SV_HANDLER_MAX (SV_TRY_MAX * 2) 329 330#define SV_FRAMES_HARD_MAX 65536 331#define SV_STACK_HARD_MAX 524288 332 333struct sv_vm { 334 ant_t *js; 335 336 ant_value_t *stack; 337 int sp; 338 int stack_size; 339 340 sv_frame_t *frames; 341 int fp; 342 int max_frames; 343 344 sv_handler_t handler_stack[SV_HANDLER_MAX]; 345 sv_upvalue_t *open_upvalues; 346 int handler_depth; 347 348 // TODO: move to nested struct 349 bool suspended; 350 bool suspended_resume_pending; 351 bool suspended_resume_is_error; 352 sv_resume_kind_t suspended_resume_kind; 353 354 int suspended_entry_fp; 355 int suspended_saved_fp; 356 ant_value_t suspended_resume_value; 357 358#ifdef ANT_JIT 359 struct { 360 bool active; 361 int64_t ip_offset; 362 ant_value_t *locals; 363 int64_t n_locals; 364 ant_value_t *vstack; 365 int64_t vstack_sp; 366 } jit_resume; 367 368 sv_jit_osr_t jit_osr; 369#endif 370}; 371 372static inline uint8_t sv_get_u8(const uint8_t *ip) { return ip[0]; } 373static inline int8_t sv_get_i8(const uint8_t *ip) { return (int8_t)ip[0]; } 374 375static inline uint16_t sv_get_u16(const uint8_t *ip) { 376 uint16_t v; memcpy(&v, ip, 2); return v; 377} 378 379static inline int16_t sv_get_i16(const uint8_t *ip) { 380 int16_t v; memcpy(&v, ip, 2); return v; 381} 382 383static inline uint32_t sv_get_u32(const uint8_t *ip) { 384 uint32_t v; memcpy(&v, ip, 4); return v; 385} 386 387static inline int32_t sv_get_i32(const uint8_t *ip) { 388 int32_t v; memcpy(&v, ip, 4); return v; 389} 390 391static inline const char *sv_atom_cstr(sv_atom_t *a, char *buf, size_t bufsz) { 392 size_t n = a->len < bufsz - 1 ? a->len : bufsz - 1; 393 memcpy(buf, a->str, n); 394 buf[n] = '\0'; 395 return buf; 396} 397 398static inline bool sv_frame_is_strict(const sv_frame_t *frame) { 399 return frame && frame->func && frame->func->is_strict; 400} 401 402static inline bool sv_slot_in_range( 403 const ant_value_t *base, size_t count, 404 const ant_value_t *slot 405) { 406 if (!base || !slot || count == 0) return false; 407 408 uintptr_t lo = (uintptr_t)base; 409 uintptr_t hi = lo + count * sizeof(*base); 410 uintptr_t addr = (uintptr_t)slot; 411 return addr >= lo && addr < hi; 412} 413 414static inline bool sv_slot_in_vm_stack(const sv_vm_t *vm, const ant_value_t *slot) { 415 return vm && sv_slot_in_range(vm->stack, (size_t)vm->stack_size, slot); 416} 417 418static inline bool sv_is_nullish_this(ant_value_t v) { 419 return 420 vtype(v) == T_UNDEF || vtype(v) == T_NULL || 421 (vtype(v) == T_OBJ && vdata(v) == 0); 422} 423 424static inline ant_value_t sv_normalize_this_for_frame(ant_t *js, sv_func_t *func, ant_value_t this_val) { 425 if (!func || func->is_arrow) return this_val; 426 if (func->is_strict) return sv_is_nullish_this(this_val) ? js_mkundef() : this_val; 427 return sv_is_nullish_this(this_val) ? js->global : this_val; 428} 429 430static inline bool sv_vm_is_strict(const sv_vm_t *vm) { 431 if (vm && vm->fp >= 0) { 432 const sv_frame_t *f = &vm->frames[vm->fp]; 433 return f->func && f->func->is_strict; 434 } 435 return false; 436} 437 438static inline sv_vm_t *sv_vm_get_active(ant_t *js) { 439 if (!js) return NULL; 440 if (js->active_async_coro) { 441 if (js->active_async_coro->sv_vm) return js->active_async_coro->sv_vm; 442 if (js->active_async_coro->owner_vm) return js->active_async_coro->owner_vm; 443 } 444 return js->vm; 445} 446 447static inline bool sv_is_strict_context(ant_t *js) { 448 return sv_vm_is_strict(sv_vm_get_active(js)); 449} 450 451static inline ant_value_t sv_vm_get_new_target(const sv_vm_t *vm, ant_t *js) { 452 if (vm && vm->fp >= 0) return vm->frames[vm->fp].new_target; 453 return js->new_target; 454} 455 456static inline ant_value_t sv_vm_get_super_val(const sv_vm_t *vm) { 457 if (vm && vm->fp >= 0) return vm->frames[vm->fp].super_val; 458 return js_mkundef(); 459} 460 461static inline int sv_frame_arg_slots(const sv_frame_t *frame) { 462 if (!frame || !frame->func) return 0; 463 return frame->argc > frame->func->param_count ? frame->argc : frame->func->param_count; 464} 465 466static inline ant_value_t sv_frame_get_arg_value(const sv_frame_t *frame, uint16_t idx) { 467 int arg_slots = sv_frame_arg_slots(frame); 468 if (!frame || !frame->bp || (int)idx >= arg_slots) return js_mkundef(); 469 return frame->bp[idx]; 470} 471 472static inline void sv_frame_set_arg_value(ant_t *js, sv_frame_t *frame, uint16_t idx, ant_value_t val) { 473 int arg_slots = sv_frame_arg_slots(frame); 474 if (!frame || !frame->bp || (int)idx >= arg_slots) return; 475 frame->bp[idx] = val; 476 if (vtype(frame->arguments_obj) != T_UNDEF) 477 js_arguments_sync_slot(js, frame->arguments_obj, idx, val); 478} 479 480static inline ant_value_t *sv_frame_slot_ptr(sv_frame_t *frame, uint16_t slot_idx) { 481 if (!frame || !frame->func) return NULL; 482 int param_count = frame->func->param_count; 483 if ((int)slot_idx < param_count) { 484 int arg_slots = sv_frame_arg_slots(frame); 485 if ((int)slot_idx >= arg_slots || !frame->bp) return NULL; 486 return &frame->bp[slot_idx]; 487 } 488 if (!frame->lp) return NULL; 489 return &frame->lp[slot_idx - param_count]; 490} 491 492static inline uint16_t sv_frame_total_slots(const sv_frame_t *frame) { 493 if (!frame || !frame->func) return 0; 494 int total = frame->func->param_count + frame->func->max_locals; 495 return total > 0 ? (uint16_t)total : 0; 496} 497 498static inline void sv_vm_maybe_checkpoint_microtasks(ant_t *js) { 499 if (!js || js->microtasks_draining || js->vm_exec_depth != 0) return; 500 js_maybe_drain_microtasks(js); 501} 502 503ant_value_t sv_string_builder_read_value( 504 ant_t *js, ant_value_t value 505); 506 507ant_value_t sv_string_builder_flush_slot( 508 sv_vm_t *vm, ant_t *js, 509 sv_frame_t *frame, uint16_t slot_idx 510); 511 512ant_value_t sv_string_builder_append_slot( 513 sv_vm_t *vm, ant_t *js, sv_frame_t *frame, 514 sv_func_t *func, uint16_t slot_idx, ant_value_t rhs 515); 516 517ant_value_t sv_string_builder_append_snapshot_slot( 518 sv_vm_t *vm, ant_t *js, sv_frame_t *frame, 519 sv_func_t *func, uint16_t slot_idx, ant_value_t lhs, ant_value_t rhs 520); 521 522typedef struct { 523 ant_value_t this_val; 524 ant_value_t super_val; 525 ant_value_t *args; 526 int argc; 527 ant_value_t *alloc; 528} sv_call_ctx_t; 529 530typedef enum { 531 SV_CALL_MODE_NORMAL = 0, 532 SV_CALL_MODE_EXPLICIT_THIS, 533 SV_CALL_MODE_CONSTRUCT, 534} sv_call_mode_t; 535 536typedef enum { 537 SV_CALL_EXEC_NATIVE = 0, 538 SV_CALL_EXEC_PROXY_APPLY, 539 SV_CALL_EXEC_PROXY_CONSTRUCT, 540 SV_CALL_EXEC_DEFAULT_CTOR, 541 SV_CALL_EXEC_CLOSURE, 542} sv_call_exec_kind_t; 543 544typedef struct { 545 sv_call_exec_kind_t kind; 546 ant_value_t func; 547 sv_closure_t *closure; 548 sv_call_ctx_t ctx; 549} sv_call_plan_t; 550 551static inline ant_value_t *sv_prepend_bound_args( 552 sv_closure_t *closure, ant_value_t *args, int argc, int *out_total 553) { 554 int total = closure->bound_argc + argc; 555 ant_value_t *combined = malloc(sizeof(ant_value_t) * (size_t)total); 556 557 if (!combined) { *out_total = argc; return NULL; } 558 memcpy(combined, closure->bound_argv, sizeof(ant_value_t) * (size_t)closure->bound_argc); 559 memcpy(combined + closure->bound_argc, args, sizeof(ant_value_t) * (size_t)argc); 560 561 *out_total = total; 562 return combined; 563} 564 565static inline bool sv_call_mode_is_construct(sv_call_mode_t mode) { 566 return mode == SV_CALL_MODE_CONSTRUCT; 567} 568 569static inline ant_value_t sv_call_normalize_this(ant_t *js, ant_value_t this_val, sv_call_mode_t mode) { 570 if (mode == SV_CALL_MODE_NORMAL && sv_is_nullish_this(this_val)) return js->global; 571 return this_val; 572} 573 574static inline ant_value_t sv_call_resolve_bound( 575 ant_t *js, sv_closure_t *closure, 576 sv_call_ctx_t *ctx, sv_call_mode_t mode 577) { 578 uint32_t flags = closure->call_flags; 579 580 if (flags & SV_CALL_IS_ARROW) ctx->this_val = closure->bound_this; 581 else if (!sv_call_mode_is_construct(mode) && vtype(closure->bound_this) != T_UNDEF) 582 ctx->this_val = closure->bound_this; 583 584 if ((flags & SV_CALL_HAS_BOUND_ARGS) && closure->bound_argc > 0) { 585 int total; 586 ant_value_t *combined = sv_prepend_bound_args(closure, ctx->args, ctx->argc, &total); 587 if (!combined) return js_mkerr(js, "out of memory"); 588 ctx->args = combined; 589 ctx->argc = total; 590 ctx->alloc = combined; 591 } 592 593 if (flags & SV_CALL_HAS_SUPER) ctx->super_val = closure->super_val; 594 return js_mkundef(); 595} 596 597static inline void sv_call_cleanup(ant_t *js, sv_call_ctx_t *ctx) { 598 if (ctx->alloc) { free(ctx->alloc); ctx->alloc = NULL; } 599} 600 601static inline ant_value_t sv_call_default_ctor( 602 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 603 sv_call_ctx_t *ctx, ant_value_t *out_this 604); 605 606static inline ant_value_t sv_call_resolve_closure( 607 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 608 ant_value_t callee_func, sv_call_ctx_t *ctx, ant_value_t *out_this 609); 610 611static inline ant_value_t sv_prepare_call( 612 sv_vm_t *vm, ant_t *js, ant_value_t func, 613 ant_value_t this_val, ant_value_t *args, int argc, 614 ant_value_t *out_this, sv_call_mode_t mode, sv_call_plan_t *plan 615) { 616 bool is_construct_call = sv_call_mode_is_construct(mode); 617 618 plan->kind = SV_CALL_EXEC_NATIVE; 619 plan->func = func; 620 plan->closure = NULL; 621 622 plan->ctx = (sv_call_ctx_t){ 623 .this_val = this_val, 624 .super_val = js_mkundef(), 625 .args = args, 626 .argc = argc, 627 .alloc = NULL, 628 }; 629 630 if (!is_construct_call) js->new_target = js_mkundef(); 631 if (out_this) *out_this = this_val; 632 633 if (is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 634 plan->kind = SV_CALL_EXEC_PROXY_CONSTRUCT; 635 return js_mkundef(); 636 } 637 638 if (is_construct_call && !js_is_constructor(func)) 639 return js_mkerr_typed(js, JS_ERR_TYPE, "not a constructor"); 640 641 if (!is_construct_call && vtype(func) == T_OBJ && is_proxy(func)) { 642 plan->kind = SV_CALL_EXEC_PROXY_APPLY; 643 return js_mkundef(); 644 } 645 646 if (vtype(func) == T_CFUNC) { 647 plan->ctx.this_val = sv_call_normalize_this(js, this_val, mode); 648 if (out_this) *out_this = plan->ctx.this_val; 649 return js_mkundef(); 650 } 651 652 if (vtype(func) != T_FUNC) 653 return js_mkerr_typed(js, JS_ERR_TYPE, "%s is not a function", typestr(vtype(func))); 654 655 sv_closure_t *closure = js_func_closure(func); 656 plan->closure = closure; 657 658 ant_value_t err = sv_call_resolve_bound(js, closure, &plan->ctx, mode); 659 if (is_err(err)) return err; 660 661 if (is_construct_call) plan->ctx.this_val = this_val; 662 if (out_this) *out_this = plan->ctx.this_val; 663 664 if (closure->call_flags & SV_CALL_IS_DEFAULT_CTOR) { 665 plan->kind = SV_CALL_EXEC_DEFAULT_CTOR; 666 return js_mkundef(); 667 } 668 669 if (closure->func != NULL) { 670 plan->kind = SV_CALL_EXEC_CLOSURE; 671 return js_mkundef(); 672 } 673 674 return js_mkundef(); 675} 676 677static inline ant_value_t sv_execute_call_plan( 678 sv_vm_t *vm, ant_t *js, sv_call_plan_t *plan, ant_value_t *out_this 679) { 680 switch (plan->kind) { 681 case SV_CALL_EXEC_PROXY_APPLY: return js_proxy_apply( 682 js, plan->func, plan->ctx.this_val, plan->ctx.args, plan->ctx.argc 683 ); 684 685 case SV_CALL_EXEC_PROXY_CONSTRUCT: return js_proxy_construct( 686 js, plan->func, plan->ctx.args, plan->ctx.argc, sv_vm_get_new_target(vm, js) 687 ); 688 689 case SV_CALL_EXEC_DEFAULT_CTOR: return sv_call_default_ctor( 690 vm, js, plan->closure, &plan->ctx, out_this 691 ); 692 693 case SV_CALL_EXEC_CLOSURE: return sv_call_resolve_closure( 694 vm, js, plan->closure, plan->func, &plan->ctx, out_this 695 ); 696 697 case SV_CALL_EXEC_NATIVE: { 698 ant_value_t result = sv_call_native( 699 js, plan->func, plan->ctx.this_val, plan->ctx.args, plan->ctx.argc 700 ); 701 sv_call_cleanup(js, &plan->ctx); 702 return result; 703 }} 704 705 return js_mkerr(js, "invalid call plan"); 706} 707 708static inline bool sv_check_c_stack_overflow(ant_t *js) { 709 volatile char marker; 710 if (js->cstk.limit == 0 || js->cstk.base == NULL) return false; 711 712 uintptr_t base = (uintptr_t)js->cstk.base; 713 uintptr_t curr = (uintptr_t)&marker; 714 715 size_t used = (base > curr) ? (base - curr) : (curr - base); 716 return used > js->cstk.limit; 717} 718 719static inline ant_value_t sv_vm_call( 720 sv_vm_t *vm, ant_t *js, ant_value_t func, 721 ant_value_t this_val, ant_value_t *args, int argc, 722 ant_value_t *out_this, bool is_construct_call 723) { 724 if (sv_check_c_stack_overflow(js)) 725 return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 726 727 sv_call_mode_t mode = is_construct_call 728 ? SV_CALL_MODE_CONSTRUCT 729 : SV_CALL_MODE_NORMAL; 730 731 sv_call_plan_t plan; 732 ant_value_t err = sv_prepare_call( 733 vm, js, func, this_val, args, argc, 734 out_this, mode, &plan 735 ); 736 737 if (is_err(err)) return err; 738 ant_value_t result = sv_execute_call_plan(vm, js, &plan, out_this); 739 sv_vm_maybe_checkpoint_microtasks(js); 740 741 return result; 742} 743 744static inline ant_value_t sv_vm_call_explicit_this( 745 sv_vm_t *vm, ant_t *js, ant_value_t func, 746 ant_value_t this_val, ant_value_t *args, int argc 747) { 748 if (sv_check_c_stack_overflow(js)) 749 return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 750 751 sv_call_plan_t plan; 752 ant_value_t err = sv_prepare_call( 753 vm, js, func, this_val, args, argc, NULL, 754 SV_CALL_MODE_EXPLICIT_THIS, &plan 755 ); 756 757 if (is_err(err)) return err; 758 ant_value_t result = sv_execute_call_plan(vm, js, &plan, NULL); 759 sv_vm_maybe_checkpoint_microtasks(js); 760 761 return result; 762} 763 764static inline ant_value_t sv_call_default_ctor( 765 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 766 sv_call_ctx_t *ctx, ant_value_t *out_this 767) { 768 if (vtype(js->new_target) == T_UNDEF) { 769 sv_call_cleanup(js, ctx); 770 return js_mkerr_typed( 771 js, JS_ERR_TYPE, 772 "Class constructor cannot be invoked without 'new'" 773 );} 774 775 ant_value_t super_ctor = closure->super_val; 776 uint8_t st = vtype(super_ctor); 777 778 if (st == T_FUNC || st == T_CFUNC) { 779 ant_value_t super_this = ctx->this_val; 780 ant_value_t result = sv_vm_call( 781 vm, js, super_ctor, ctx->this_val, 782 ctx->args, ctx->argc, &super_this, true 783 ); 784 785 if (out_this) *out_this = super_this; 786 sv_call_cleanup(js, ctx); 787 788 return result; 789 } 790 791 sv_call_cleanup(js, ctx); 792 return js_mkundef(); 793} 794 795ant_value_t sv_call_async_closure_dispatch( 796 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 797 ant_value_t callee_func, ant_value_t super_val, 798 ant_value_t this_val, ant_value_t *args, int argc 799); 800 801ant_value_t sv_call_generator_closure_dispatch( 802 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 803 ant_value_t callee_func, ant_value_t super_val, 804 ant_value_t this_val, ant_value_t *args, int argc 805); 806 807static inline ant_value_t sv_call_async_closure( 808 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 809 ant_value_t callee_func, sv_call_ctx_t *ctx 810) { 811 ant_value_t result = sv_call_async_closure_dispatch( 812 vm, js, closure, callee_func, 813 ctx->super_val, ctx->this_val, ctx->args, ctx->argc 814 ); 815 sv_call_cleanup(js, ctx); 816 return result; 817} 818 819static inline ant_value_t sv_call_generator_closure( 820 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 821 ant_value_t callee_func, sv_call_ctx_t *ctx 822) { 823 ant_value_t result = sv_call_generator_closure_dispatch( 824 vm, js, closure, callee_func, 825 ctx->super_val, ctx->this_val, ctx->args, ctx->argc 826 ); 827 sv_call_cleanup(js, ctx); 828 return result; 829} 830 831static inline ant_value_t sv_call_closure( 832 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 833 ant_value_t callee_func, sv_call_ctx_t *ctx, ant_value_t *out_this 834) { 835 ant_value_t result = sv_execute_closure_entry( 836 vm, closure, callee_func, ctx->super_val, 837 ctx->this_val, ctx->args, ctx->argc, out_this 838 ); 839 sv_call_cleanup(js, ctx); 840 return result; 841} 842 843#ifdef ANT_JIT 844 845#define SV_TFB_NUM (1 << 0) 846#define SV_TFB_STR (1 << 1) 847#define SV_TFB_BOOL (1 << 2) 848#define SV_TFB_OTHER (1 << 3) 849#define SV_TFB_CTOR_PROP_BINS 17 850#define SV_TFB_CTOR_PROP_OVERFLOW_FROM (SV_TFB_CTOR_PROP_BINS - 1) 851#define SV_TFB_INOBJ_SLACK_ALLOCATIONS 32 852#define SV_TFB_INOBJ_P90_NUMERATOR 9 853#define SV_TFB_INOBJ_P90_DENOMINATOR 10 854 855#define SV_JIT_THRESHOLD 100 856#define SV_JIT_RECOMPILE_DELAY 50 857#define SV_TFB_ALLOC_THRESHOLD 2 858 859#define SV_CALL_FB_MAX_SLOTS 32 860#define SV_CALL_FB_MISS_DISABLE 4 861 862#define SV_JIT_RETRY_INTERP mkval(T_ERR, 1) 863#define SV_JIT_MAGIC 0xBA110ULL 864 865#define SV_JIT_BAILOUT \ 866 (NANBOX_PREFIX \ 867 | ((ant_value_t)T_SENTINEL << NANBOX_TYPE_SHIFT) \ 868 | SV_JIT_MAGIC) 869 870static inline bool sv_is_jit_bailout(ant_value_t v) { 871 return v == SV_JIT_BAILOUT; 872} 873 874static inline void sv_jit_enter(ant_t *js) { 875 if (js) js->jit_active_depth++; 876} 877 878static inline void sv_jit_leave(ant_t *js) { 879 if (js && js->jit_active_depth > 0) js->jit_active_depth--; 880} 881 882static inline void sv_jit_on_bailout(sv_func_t *fn) { 883 fn->jit_code = NULL; 884 fn->back_edge_count = 0; 885 fn->call_count = SV_JIT_THRESHOLD - SV_JIT_RECOMPILE_DELAY; 886} 887 888typedef ant_value_t (*sv_jit_func_t)( 889 sv_vm_t *, 890 ant_value_t, 891 ant_value_t, 892 ant_value_t, 893 ant_value_t *, 894 int, sv_closure_t * 895); 896 897ant_value_t sv_jit_try_compile_and_call(sv_vm_t *vm, ant_t *js, 898 sv_closure_t *closure, ant_value_t callee_func, 899 sv_call_ctx_t *ctx, ant_value_t *out_this 900); 901 902static inline uint8_t sv_tfb_classify(ant_value_t v) { 903 if (vtype(v) == T_NUM) return SV_TFB_NUM; 904 if (vtype(v) == T_STR) return SV_TFB_STR; 905 if (vtype(v) == T_BOOL) return SV_TFB_BOOL; 906 return SV_TFB_OTHER; 907} 908 909static inline void sv_tfb_record2(sv_func_t *func, uint8_t *ip, ant_value_t l, ant_value_t r) { 910if (func->type_feedback) { 911 int off = (int)(ip - func->code); 912 uint8_t old = func->type_feedback[off]; 913 uint8_t neu = old | sv_tfb_classify(l) | sv_tfb_classify(r); 914 if (neu != old) { func->type_feedback[off] = neu; func->tfb_version++; } 915}} 916 917static inline void sv_tfb_record1(sv_func_t *func, uint8_t *ip, ant_value_t v) { 918if (func->type_feedback) { 919 int off = (int)(ip - func->code); 920 uint8_t old = func->type_feedback[off]; 921 uint8_t neu = old | sv_tfb_classify(v); 922 if (neu != old) { func->type_feedback[off] = neu; func->tfb_version++; } 923}} 924 925static inline void sv_tfb_seed_param_hints(sv_func_t *fn) { 926 if (!fn->param_type_feedback || !fn->param_hints) return; 927 int n = fn->param_hint_count < fn->param_count 928 ? fn->param_hint_count : fn->param_count; 929 for (int i = 0; i < n; i++) { 930 if (fn->param_hints[i].type == SV_TI_NUM) 931 fn->param_type_feedback[i] |= SV_TFB_NUM; 932 } 933} 934 935static inline void sv_tfb_ensure(sv_func_t *fn) { 936 if (!fn->type_feedback && fn->code_len > 0) 937 fn->type_feedback = calloc((size_t)fn->code_len, 1); 938 if (!fn->local_type_feedback && fn->max_locals > 0) 939 fn->local_type_feedback = calloc((size_t)fn->max_locals, 1); 940 if (!fn->param_type_feedback && fn->param_count > 0) { 941 fn->param_type_feedback = calloc((size_t)fn->param_count, 1); 942 sv_tfb_seed_param_hints(fn); 943 } 944} 945 946static inline void sv_tfb_record_param(sv_func_t *func, int idx, ant_value_t v) { 947 if (func->param_type_feedback && idx >= 0 && idx < func->param_count) { 948 uint8_t old = func->param_type_feedback[idx]; 949 uint8_t neu = old | sv_tfb_classify(v); 950 if (neu != old) { func->param_type_feedback[idx] = neu; func->tfb_version++; } 951 } 952} 953 954static inline bool sv_tfb_param_numeric_hint(const sv_func_t *func, int idx) { 955 if (!func || idx < 0 || idx >= func->param_count) return false; 956 uint8_t fb = func->param_type_feedback ? func->param_type_feedback[idx] : 0; 957 if (fb && (fb & ~SV_TFB_NUM)) return false; 958 if (fb == SV_TFB_NUM) return true; 959 return ( 960 func->param_hints && 961 idx < func->param_hint_count && 962 func->param_hints[idx].type == SV_TI_NUM 963 ); 964} 965 966static inline void sv_tfb_record_call_target(sv_func_t *func, int bc_off, sv_func_t *callee) { 967 if (!callee) return; 968 sv_call_target_fb_t *fb = func->call_target_fb; 969 int count = func->call_target_fb_count; 970 for (int i = 0; i < count; i++) { 971 if (fb[i].bc_off != (uint16_t)bc_off) continue; 972 if (fb[i].disabled) return; 973 if (fb[i].target == callee) return; 974 if (fb[i].target == NULL) { fb[i].target = callee; return; } 975 fb[i].miss_count++; 976 if (fb[i].miss_count >= SV_CALL_FB_MISS_DISABLE) { 977 fb[i].disabled = 1; 978 fb[i].target = NULL; 979 } else { 980 fb[i].target = callee; 981 } 982 func->tfb_version++; 983 return; 984 } 985 if (count >= SV_CALL_FB_MAX_SLOTS) return; 986 if (!fb) { 987 fb = calloc(SV_CALL_FB_MAX_SLOTS, sizeof(sv_call_target_fb_t)); 988 if (!fb) return; 989 func->call_target_fb = fb; 990 } 991 fb[count].bc_off = (uint16_t)bc_off; 992 fb[count].target = callee; 993 fb[count].miss_count = 0; 994 fb[count].disabled = 0; 995 func->call_target_fb_count = (uint8_t)(count + 1); 996} 997 998static inline sv_func_t *sv_tfb_get_call_target(sv_func_t *func, int bc_off) { 999 sv_call_target_fb_t *fb = func->call_target_fb; 1000 int count = func->call_target_fb_count; 1001 for (int i = 0; i < count; i++) { 1002 if (fb[i].bc_off == (uint16_t)bc_off && !fb[i].disabled) 1003 return fb[i].target; 1004 } 1005 return NULL; 1006} 1007 1008static inline void sv_tfb_record_local(sv_func_t *func, int idx, ant_value_t v) { 1009 if (func->local_type_feedback && idx >= 0 && idx < func->max_locals) { 1010 uint8_t old = func->local_type_feedback[idx]; 1011 uint8_t neu = old | sv_tfb_classify(v); 1012 if (neu != old) { func->local_type_feedback[idx] = neu; func->tfb_version++; } 1013 } 1014} 1015 1016static inline uint8_t sv_tfb_clamp_inobj_limit(uint32_t limit) { 1017 return (limit > ANT_INOBJ_MAX_SLOTS) ? (uint8_t)ANT_INOBJ_MAX_SLOTS : (uint8_t)limit; 1018} 1019 1020static inline uint8_t sv_tfb_infer_inobj_limit(const sv_func_t *func, uint64_t samples) { 1021 if (!func || samples == 0) return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1022 1023 uint64_t target = ( 1024 (samples * SV_TFB_INOBJ_P90_NUMERATOR) 1025 + (SV_TFB_INOBJ_P90_DENOMINATOR - 1) 1026 ) / SV_TFB_INOBJ_P90_DENOMINATOR; 1027 if (target == 0) target = 1; 1028 1029 uint64_t seen = 0; 1030 for (uint32_t i = 0; i < SV_TFB_CTOR_PROP_BINS; i++) { 1031 seen += func->ctor_prop_hist[i]; 1032 if (seen < target) continue; 1033 1034 if (i >= SV_TFB_CTOR_PROP_OVERFLOW_FROM) return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1035 return sv_tfb_clamp_inobj_limit(i); 1036 } 1037 1038 return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1039} 1040 1041static inline void sv_tfb_record_ctor_prop_count(ant_value_t ctor_func, ant_value_t instance) { 1042 if (vtype(ctor_func) != T_FUNC) return; 1043 if (!is_object_type(instance)) return; 1044 sv_closure_t *closure = js_func_closure(ctor_func); 1045 if (!closure || !closure->func) return; 1046 ant_object_t *obj = js_obj_ptr(js_as_obj(instance)); 1047 if (!obj) return; 1048 1049 sv_func_t *func = closure->func; 1050 uint32_t count = obj->prop_count; 1051 uint32_t bin = (count < SV_TFB_CTOR_PROP_OVERFLOW_FROM) 1052 ? count 1053 : SV_TFB_CTOR_PROP_OVERFLOW_FROM; 1054 func->ctor_prop_hist[bin]++; 1055 uint64_t samples = ++func->ctor_prop_samples; 1056 if (!func->ctor_inobj_frozen && samples >= SV_TFB_INOBJ_SLACK_ALLOCATIONS) { 1057 func->ctor_inobj_limit = sv_tfb_infer_inobj_limit(func, samples); 1058 func->ctor_inobj_frozen = 1; 1059 } 1060} 1061 1062static inline uint8_t sv_tfb_ctor_inobj_limit(ant_value_t ctor_func) { 1063 if (vtype(ctor_func) != T_FUNC) return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1064 sv_closure_t *closure = js_func_closure(ctor_func); 1065 if (!closure || !closure->func) return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1066 1067 sv_func_t *func = closure->func; 1068 if (!func->ctor_inobj_frozen) return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1069 return sv_tfb_clamp_inobj_limit(func->ctor_inobj_limit); 1070} 1071 1072static inline bool sv_tfb_ctor_inobj_limit_frozen(ant_value_t ctor_func) { 1073 if (vtype(ctor_func) != T_FUNC) return false; 1074 sv_closure_t *closure = js_func_closure(ctor_func); 1075 if (!closure || !closure->func) return false; 1076 return closure->func->ctor_inobj_frozen != 0; 1077} 1078 1079static inline uint32_t sv_tfb_ctor_inobj_slack_remaining(ant_value_t ctor_func) { 1080 if (vtype(ctor_func) != T_FUNC) return SV_TFB_INOBJ_SLACK_ALLOCATIONS; 1081 sv_closure_t *closure = js_func_closure(ctor_func); 1082 if (!closure || !closure->func) return SV_TFB_INOBJ_SLACK_ALLOCATIONS; 1083 sv_func_t *func = closure->func; 1084 if (func->ctor_inobj_frozen || func->ctor_prop_samples >= SV_TFB_INOBJ_SLACK_ALLOCATIONS) return 0; 1085 return (uint32_t)(SV_TFB_INOBJ_SLACK_ALLOCATIONS - func->ctor_prop_samples); 1086} 1087#endif 1088 1089#ifndef ANT_JIT 1090static inline void sv_tfb_record_ctor_prop_count(ant_value_t ctor_func, ant_value_t instance) { 1091 (void)ctor_func; 1092 (void)instance; 1093} 1094 1095static inline uint8_t sv_tfb_ctor_inobj_limit(ant_value_t ctor_func) { 1096 (void)ctor_func; 1097 return (uint8_t)ANT_INOBJ_MAX_SLOTS; 1098} 1099 1100static inline bool sv_tfb_ctor_inobj_limit_frozen(ant_value_t ctor_func) { 1101 (void)ctor_func; 1102 return false; 1103} 1104 1105static inline uint32_t sv_tfb_ctor_inobj_slack_remaining(ant_value_t ctor_func) { 1106 (void)ctor_func; 1107 return 0; 1108} 1109#endif 1110 1111static inline ant_value_t sv_call_resolve_closure( 1112 sv_vm_t *vm, ant_t *js, sv_closure_t *closure, 1113 ant_value_t callee_func, sv_call_ctx_t *ctx, ant_value_t *out_this 1114) { 1115 if (closure->func->is_generator) 1116 return sv_call_generator_closure(vm, js, closure, callee_func, ctx); 1117 if (closure->func->is_async) 1118 return sv_call_async_closure(vm, js, closure, callee_func, ctx); 1119#ifdef ANT_JIT 1120 if (!closure->func->is_generator) { 1121 sv_func_t *fn = closure->func; 1122 if (fn->jit_code) { 1123 sv_jit_enter(js); 1124 ant_value_t result = ((sv_jit_func_t)fn->jit_code)( 1125 vm, ctx->this_val, js->new_target, 1126 ctx->super_val, ctx->args, ctx->argc, closure 1127 ); 1128 sv_jit_leave(js); 1129 if (sv_is_jit_bailout(result)) { 1130 sv_jit_on_bailout(fn); 1131 } else { sv_call_cleanup(js, ctx); return result; } 1132 } 1133 { 1134 uint32_t cc = ++fn->call_count; 1135 if (__builtin_expect(cc == SV_TFB_ALLOC_THRESHOLD, 0)) 1136 sv_tfb_ensure(fn); 1137 if (cc > SV_JIT_THRESHOLD) { 1138 ant_value_t result = sv_jit_try_compile_and_call(vm, js, closure, callee_func, ctx, out_this); 1139 if (result != SV_JIT_RETRY_INTERP) return result; 1140 } 1141 } 1142 } 1143#endif 1144 return sv_call_closure(vm, js, closure, callee_func, ctx, out_this); 1145} 1146 1147#endif