Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293#ifndef SILVER_ENGINE_H#define SILVER_ENGINE_H
#include "silver/vm.h"#include "internal.h"#include "runtime.h"#include "errors.h"
#include "gc.h"#include "gc/objects.h"
#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <stdio.h>
static constexpr int SV_JIT_ARGS_BUF_CAP = 16;
static constexpr uint8_t SV_MAP_TEMPLATE_MAX_SUBSTITUTIONS = 3;static constexpr uint32_t SV_MAP_TEMPLATE_TABLE_MAGIC = UINT32_C(0x4d54504c);
static constexpr uint8_t SV_CLASS_FLAG_HAS_NAME = 1u << 0;static constexpr uint8_t SV_CLASS_FLAG_HAS_HERITAGE = 1u << 1;
typedef enum { SV_DEFINE_METHOD_GETTER = 1u << 0, SV_DEFINE_METHOD_SETTER = 1u << 1, SV_DEFINE_METHOD_SET_NAME = 1u << 2, SV_DEFINE_METHOD_NON_ENUM = 1u << 3,} sv_define_method_flags_t;
typedef enum { SV_OPF_JIT_ELIGIBLE = 1u << 0, SV_OPF_JIT_INLINEABLE = 1u << 1, SV_OPF_JIT_NEEDS_BAILOUT = 1u << 2, SV_OPF_JIT_NEEDS_INC_LOCAL = 1u << 3, SV_OPF_JIT_NEEDS_ARGS_BUF = 1u << 4, SV_OPF_JIT_NEEDS_TCO_ARGS = 1u << 5, SV_OPF_JIT_NEEDS_ITER_ROOTS = 1u << 6, SV_OPF_JIT_NEEDS_CLOSE_UPVAL = 1u << 7, SV_OPF_JIT_NEEDS_IC_EPOCH = 1u << 8, SV_OPF_JIT_LOCAL_NUMERIC_BAILOUT = 1u << 9, SV_OPF_JIT_BRANCH32 = 1u << 10, SV_OPF_JIT_BRANCH8 = 1u << 11, SV_OPF_JIT_OSR_BACKEDGE = 1u << 12, SV_OPF_BUILDER_TARGET = 1u << 13, SV_OPF_JIT_INLINE_ARGC = 1u << 14, SV_OPF_TERMINAL = 1u << 15,} sv_opcode_flags_t;
typedef enum {#define OP_DEF(name, size, n_pop, n_push, f) OP_##name,#include "silver/opcode.h" OP__COUNT} sv_op_t;
typedef enum { SV_SPECIAL_ARGUMENTS = 0, SV_SPECIAL_NEW_TARGET = 1, SV_SPECIAL_SUPER = 2, SV_SPECIAL_MODULE_IMPORT = 3, SV_SPECIAL_ARGC = 4,} sv_special_obj_t;
typedef enum { SV_STABLE_BUILTIN_PROMISE_RESOLVE = 0,} sv_stable_builtin_t;
extern const char *const sv_op_names[OP__COUNT];
bool sv_op_stack_effect( const sv_func_t *func, const uint8_t *ip, int *pops, int *pushes);
int *sv_func_stack_depth_map(const sv_func_t *func);int *sv_func_try_map(const sv_func_t *func);
static const uint8_t sv_op_size[OP__COUNT] = {#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = (size),#include "silver/opcode.h"};
enum {#define OP_FMT(name) SVF_##name,#include "silver/opcode.h" SVF__COUNT,};
static const uint8_t sv_op_fmts[OP__COUNT] = {#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = SVF_##f,#include "silver/opcode.h"};
static const uint16_t sv_op_flags[OP__COUNT] = {#define OP_FLAG(name, flags) [OP_##name] = (flags),#include "silver/opcode.h"};
static const bool sv_op_ic_slots[OP__COUNT] = {#define OP_IC_SLOT(name) [OP_##name] = true,#include "silver/opcode.h"};
typedef struct { const char *str; uint32_t len; bool maybe_numeric;} sv_atom_t;
static inline bool sv_op_has_ic_slot(sv_op_t op) { return (unsigned)op < OP__COUNT && sv_op_ic_slots[op];}
static inline sv_atom_t sv_length_atom(ant_t *js) { return (sv_atom_t){ js->intern.length, 6, false };}
typedef enum { SV_MAP_TEMPLATE_GET = 0, SV_MAP_TEMPLATE_HAS,} sv_map_template_operation_t;
typedef struct sv_map_template_desc { sv_atom_t segments[SV_MAP_TEMPLATE_MAX_SUBSTITUTIONS + 1]; uint8_t substitution_count; uint8_t operation;} sv_map_template_desc_t;
typedef struct { uint32_t count; uint32_t magic;} sv_map_template_table_header_t;
static inline bool sv_map_template_is_canonical_pair_get( const sv_map_template_desc_t *desc) { return desc && desc->operation == SV_MAP_TEMPLATE_GET && desc->substitution_count == 2 && desc->segments[0].len == 0 && desc->segments[2].len == 0;}
static_assert( _Alignof(sv_map_template_desc_t) <= CODE_ARENA_ALIGNMENT, "map template descriptor alignment exceeds the code arena guarantee");
static_assert( sizeof(sv_map_template_table_header_t) % _Alignof(sv_map_template_desc_t) == 0, "map template table header must preserve descriptor alignment");
#ifndef ANT_WASM_EMBEDstatic_assert( UINT32_MAX <= SIZE_MAX / sizeof(sv_map_template_desc_t), "map template descriptor table must fit in size_t");#endif
typedef struct { uint16_t index; bool is_local: 1; bool is_const: 1; bool may_tdz: 1;} sv_upval_desc_t;
static_assert( sizeof(sv_upval_desc_t) == 4, "sv_upval_desc_t must stay 4 bytes");
typedef struct { uint32_t bc_offset; uint32_t line; uint32_t col; uint32_t src_off; uint32_t src_end;} sv_srcpos_t;
typedef enum { SV_TI_UNKNOWN = 0, SV_TI_NUM, SV_TI_STR, SV_TI_ARR, SV_TI_OBJ, SV_TI_BOOL, SV_TI_NULL, SV_TI_UNDEF,} sv_local_type_t;
typedef struct { uint8_t type: 6; bool bound: 1; bool shared_slot: 1;} sv_type_info_t;
static_assert( sizeof(sv_type_info_t) == 1, "sv_type_info_t must stay one byte");
typedef enum: uint8_t { SV_GF_IC_OWN = 0, SV_GF_IC_PROTOTYPE, SV_GF_IC_MISSING, SV_GF_IC_PRIMITIVE_DATA, SV_GF_IC_PRIMITIVE_MISSING, SV_GF_IC_SYMBOL_DESCRIPTION, SV_GF_IC_PRIMITIVE_SYMBOL_DESCRIPTION, SV_GF_IC_OWN_GETTER, SV_GF_IC_PROTO_GETTER,} sv_get_field_ic_kind_t;
typedef enum: uint8_t { SV_IC_SHAPE_REF_CACHED = 1u << 0, SV_IC_SHAPE_REF_ADD_FROM = 1u << 1, SV_IC_SHAPE_REF_ADD_TO = 1u << 2, SV_IC_POLY_MEGA = 1u << 3, SV_IC_MEGA_COMPILED = 1u << 4, SV_IC_HAS_GET_POLY = 1u << 5, SV_IC_HAS_PUT_POLY = 1u << 6, SV_IC_UNIT_OWNED = 1u << 7,} sv_ic_flags_t;
static_assert( (SV_IC_SHAPE_REF_CACHED | SV_IC_SHAPE_REF_ADD_FROM | SV_IC_SHAPE_REF_ADD_TO | SV_IC_POLY_MEGA | SV_IC_MEGA_COMPILED | SV_IC_HAS_GET_POLY | SV_IC_HAS_PUT_POLY | SV_IC_UNIT_OWNED) == (SV_IC_SHAPE_REF_CACHED + SV_IC_SHAPE_REF_ADD_FROM + SV_IC_SHAPE_REF_ADD_TO + SV_IC_POLY_MEGA + SV_IC_MEGA_COMPILED + SV_IC_HAS_GET_POLY + SV_IC_HAS_PUT_POLY + SV_IC_UNIT_OWNED), "IC flags must not share bits");
static constexpr uint32_t SV_IC_IDENTITY_MAX = UINTPTR_MAX > UINT32_MAX ? UINT32_MAX : (uint32_t)(UINTPTR_MAX >> 1);
typedef struct { ant_shape_t *shape; ant_value_t receiver_proto; ant_object_t *holder; uint32_t index; uint32_t proto_id; uint32_t epoch; sv_get_field_ic_kind_t kind;} sv_gf_poly_entry_t;
static constexpr unsigned SV_GF_POLY_WAYS = 8;static constexpr unsigned SV_GF_MEGA_PRIMARY = 4096;static constexpr unsigned SV_GF_MEGA_SECONDARY = 1024;
static_assert((SV_GF_MEGA_PRIMARY & (SV_GF_MEGA_PRIMARY - 1)) == 0, "mega tables are masked");static_assert((SV_GF_MEGA_SECONDARY & (SV_GF_MEGA_SECONDARY - 1)) == 0, "mega tables are masked");
static constexpr unsigned SV_GF_MEGA_SHAPE_SHIFT = 4;static constexpr unsigned SV_GF_MEGA_KEY_SHIFT = 3;static constexpr unsigned SV_GF_MEGA_PROTO_SHIFT = 5;static constexpr unsigned SV_GF_MEGA_MIX_SHIFT = 13;
typedef struct { ant_shape_t *shape; ant_value_t receiver_proto; const char *key; ant_object_t *holder; uint32_t index; uint32_t proto_id; uint32_t epoch; sv_get_field_ic_kind_t kind;} sv_gf_mega_entry_t;
struct sv_gf_mega_cache { sv_gf_mega_entry_t primary[SV_GF_MEGA_PRIMARY]; sv_gf_mega_entry_t secondary[SV_GF_MEGA_SECONDARY];};
sv_gf_mega_cache_t *sv_gf_mega_ensure(ant_t *js);void sv_gf_mega_clear(ant_t *js);void sv_ic_polys_release_shapes(ant_t *js);void sv_ic_identities_reset(ant_t *js);
struct sv_gf_poly { sv_gf_poly_entry_t entries[SV_GF_POLY_WAYS]; uint8_t next; uint32_t kept; uint32_t kept_epoch; sv_gf_poly_t *prev, *link_next;};
typedef struct { ant_shape_t *shape; ant_shape_t *to_shape; uint32_t index; uint32_t epoch; uintptr_t proto; bool add;} sv_pf_poly_entry_t;
struct sv_pf_poly { sv_pf_poly_entry_t entries[SV_GF_POLY_WAYS]; uint8_t next; uint32_t kept; uint32_t kept_epoch; sv_pf_poly_t *prev, *link_next;};
static_assert( offsetof(sv_gf_poly_t, entries) == 0, "compiled code walks poly entries from the block");
typedef struct { ant_shape_t *cached_shape; uint32_t cached_index; uint32_t epoch; sv_get_field_ic_kind_t get_kind; sv_ic_flags_t shape_ref_mask; uint16_t slow_hits; uint32_t prototype_epoch;
union { ant_object_t *cached_holder; sv_pf_poly_t *put_poly; }; union { uintptr_t cached_aux; uintptr_t add_proto; }; // Each IC slot belongs to one bytecode site/op. Field reads use receiver_proto // as documented by get_kind; property-add ICs use add, comparisons use comparison. // Comparison ICs need both their direct prototype and object-lifetime epoch. union { ant_value_t receiver_proto; struct { ant_value_t receiver_proto; sv_gf_poly_t *poly; } get; struct { ant_shape_t *from_shape; ant_shape_t *to_shape; uint32_t slot; uint32_t epoch; } add; struct { ant_value_t receiver_proto; uint32_t object_epoch; } comparison; } guard; #ifdef ANT_WASM_EMBED uint32_t wasm32_proto_identity; uint8_t wasm32_cacheline_padding[12];#endif} sv_ic_entry_t;
static_assert( sizeof(sv_ic_entry_t) == 64, "IC entries must remain 64 bytes");
sv_gf_poly_t *sv_gf_poly_new(ant_t *js, sv_ic_entry_t *ic);sv_pf_poly_t *sv_pf_poly_new(ant_t *js, sv_ic_entry_t *ic);
void sv_gf_poly_free(ant_t *js, sv_ic_entry_t *ic);void sv_pf_poly_free(ant_t *js, sv_ic_entry_t *ic);void sv_ic_polys_cleanup(ant_t *js);
static_assert( offsetof(sv_ic_entry_t, get_kind) < 24 && offsetof(sv_ic_entry_t, epoch) < 24 && offsetof(sv_ic_entry_t, cached_shape) < 24, "IC read guards must remain in the first 24 bytes");
bool sv_ic_shape_ref_register(ant_t *js, ant_shape_t **slot);bool sv_ic_shape_ref_reserve(ant_t *js, size_t count);void sv_ic_shape_refs_cleanup(ant_t *js);
typedef struct { uint32_t bc_off; ant_shape_t *shared_shape; const uint32_t *key_atoms; uint16_t key_count; bool shape_build_failed; ant_value_t literal_template;} sv_obj_site_cache_t;
static constexpr uint32_t SV_GF_IC_AUX_MISS_SHIFT = 8u;static constexpr uint32_t SV_GF_IC_PROTO_ID_SHIFT = 32u;static constexpr uint32_t SV_GF_IC_WARMUP_ENABLE = 16u;static constexpr uint32_t SV_GF_IC_MISS_DISABLE = 4u;
static constexpr uintptr_t SV_GF_IC_AUX_WARMUP_MASK = (uintptr_t)0xFFu;static constexpr uintptr_t SV_GF_IC_AUX_MISS_MASK = (uintptr_t)0xFF00u;static constexpr uintptr_t SV_GF_IC_AUX_ACTIVE_BIT = (uintptr_t)0x10000u;
#define SV_IC_SHAPE_SLOT_DEAD ((ant_shape_t *)(uintptr_t)1)#define SV_GF_IC_AUX_ALL_MASK (SV_GF_IC_AUX_WARMUP_MASK | SV_GF_IC_AUX_MISS_MASK | SV_GF_IC_AUX_ACTIVE_BIT)
static inline uint8_t sv_gf_ic_warmup(uintptr_t aux) { return (uint8_t)(aux & SV_GF_IC_AUX_WARMUP_MASK);}
static inline uint8_t sv_gf_ic_miss_streak(uintptr_t aux) { return (uint8_t)((aux & SV_GF_IC_AUX_MISS_MASK) >> SV_GF_IC_AUX_MISS_SHIFT);}
static inline bool sv_gf_ic_active(uintptr_t aux) { return (aux & SV_GF_IC_AUX_ACTIVE_BIT) != 0;}
static inline bool sv_gf_kind_is_own(sv_get_field_ic_kind_t kind) { return kind == SV_GF_IC_OWN || kind == SV_GF_IC_OWN_GETTER;}
static inline bool sv_gf_kind_is_proto(sv_get_field_ic_kind_t kind) { return kind == SV_GF_IC_PROTOTYPE || kind == SV_GF_IC_PROTO_GETTER;}
static inline bool sv_gf_kind_is_symbol_description(sv_get_field_ic_kind_t kind) { return kind == SV_GF_IC_SYMBOL_DESCRIPTION || kind == SV_GF_IC_PRIMITIVE_SYMBOL_DESCRIPTION;}
static inline uintptr_t sv_gf_ic_pack_aux(uint8_t warmup, uint8_t miss_streak, bool active) { uintptr_t aux = ((uintptr_t)warmup & SV_GF_IC_AUX_WARMUP_MASK) | ((uintptr_t)miss_streak << SV_GF_IC_AUX_MISS_SHIFT); if (active) aux |= SV_GF_IC_AUX_ACTIVE_BIT; return aux;}
const sv_srcpos_t *sv_srcpos_at(sv_func_t *func, int bc_offset);bool sv_lookup_srcpos(sv_func_t *func, int bc_offset, uint32_t *line, uint32_t *col);bool sv_lookup_srcspan(sv_func_t *func, int bc_offset, uint32_t *src_off, uint32_t *src_end);ant_value_t Ant_Value_LooseEquals(ant_t *js, ant_value_t l, ant_value_t r);
typedef struct { uint16_t bc_off; uint8_t miss_count; uint8_t disabled; sv_func_t *target;} sv_call_target_fb_t;
typedef struct { uint8_t *type_feedback; uint8_t *elem_types; ant_shape_t *ctor_proto_shape; uint32_t ctor_proto_slot; bool ctor_proto_shape_registered; uint8_t poly_recompiles; struct sv_jit_await_map *jit_await_map; const struct sv_try_table *try_table;} sv_func_sidecar_t;
static_assert( _Alignof(sv_func_sidecar_t) > ant_sidecar, "function sidecar pointer uses low-bit tag");
typedef struct { const char *name; uint32_t len; uint16_t index; uint8_t kind; bool is_const; const char *import_name; uint32_t import_len;} sv_runtime_binding_t;
typedef struct { const sv_runtime_binding_t *bindings; uint32_t count;} sv_eval_scope_t;
enum { SV_EVAL_BIND_PARAM = 0, SV_EVAL_BIND_LOCAL = 1, SV_EVAL_BIND_UPVALUE = 2, SV_EVAL_BIND_KIND_MASK = 3, SV_EVAL_BIND_LEXICAL = 4, SV_EVAL_BIND_CATCH = 8, SV_EVAL_BIND_IMPORT_DEFAULT = 16, SV_EVAL_BIND_IMPORT_NAMED = 32,};
typedef struct { const char *str; uint32_t len; bool annex_b; bool is_const;} sv_eval_decl_t;
typedef struct { sv_eval_scope_t *eval_scopes; uint32_t eval_scope_count; sv_eval_decl_t *eval_vars; uint32_t eval_var_count; sv_eval_decl_t *global_lexicals; uint32_t global_lexical_count; sv_type_info_t local_types[];} sv_func_metadata_t;
static_assert( _Alignof(sv_func_metadata_t) <= CODE_ARENA_ALIGNMENT, "function metadata alignment exceeds the code arena guarantee");
typedef struct { const char *name; const char *display_name; const char *filename; sv_srcpos_t *srcpos; const char *source; bool display_name_varies; int srcpos_count; int source_line; int source_len; int source_start; int source_end;} sv_func_debug_t;
typedef ant_value_t (*sv_jit_func_t)( sv_vm_t *, ant_value_t, ant_value_t, ant_value_t, ant_value_t *, int, sv_closure_t *);
struct sv_func { uint8_t *code; ant_value_t *constants;
struct sv_func **child_funcs; struct sv_func *parent; uint32_t *gc_const_slots;
sv_atom_t *atoms; sv_ic_entry_t *ic_slots; sv_obj_site_cache_t *obj_sites; sv_upval_desc_t *upval_descs; sv_func_debug_t *debug; ant_realm_t *realm;
union { sv_type_info_t *local_types; sv_func_metadata_t *metadata; } type_data;
sv_jit_func_t jit_code; uint8_t *type_feedback; uint8_t *local_type_feedback; sv_call_target_fb_t *call_target_fb; uint64_t gc_epoch;
int code_len; int const_count; int child_func_count; int gc_const_slot_count; int atom_count; int max_locals; int max_stack; int local_type_count; int upvalue_count;
uint32_t obj_site_count; uint16_t ic_count; uint16_t param_count; uint16_t function_length;
bool is_strict: 1; bool is_arrow: 1; bool is_async: 1; bool has_await: 1; bool is_generator: 1; bool is_method: 1; bool is_static: 1; bool is_tla: 1; bool is_derived_ctor: 1; bool is_class_ctor: 1; bool has_dynamic_eval: 1; bool is_curried_step: 1; bool is_fusable_leaf: 1; bool has_try: 1;
bool jit_compile_failed: 1; bool jit_compiling: 1; bool jit_loop_hot: 1; bool jit_code_cold: 1; bool jit_code_retier: 1; bool has_closure: 1; bool multi_closure: 1; bool jit_tdz_specialized: 1; bool jit_await_park: 1; bool jit_async_direct_off: 1;
uint8_t jit_param_counters_off; uint8_t jit_async_direct_awaits; uint8_t jit_snapshot_resets;
uint32_t call_count; uint32_t back_edge_count; uint32_t jit_osr_threshold; uint32_t jit_bailout_tfb_ver; uint32_t tfb_version; uint32_t jit_compiled_tfb_ver;
uint8_t jit_bailout_count; uint8_t call_target_fb_count;
bool is_eval: 1; bool needs_eval_env: 1; bool allows_new_target: 1; bool has_map_templates: 1;
bool jit_inline_reuse_checked: 1; bool jit_inline_reuse_empty: 1; bool fb_unit_watched: 1; bool fb_unit_target: 1;
sv_code_unit_t *unit; struct sv_func *unit_next;};
static_assert( sizeof(void *) != 8 || sizeof(sv_func_t) <= 232, "sv_func_t must not grow past 232 bytes on 64-bit targets");
static inline const sv_map_template_desc_t *sv_map_template_desc_at( const sv_func_t *func, uint32_t index) { if (!func || !func->has_map_templates || !func->code) return NULL;
const sv_map_template_table_header_t *header = (const sv_map_template_table_header_t *)(const void *)( func->code - sizeof(sv_map_template_table_header_t)); if (header->magic != SV_MAP_TEMPLATE_TABLE_MAGIC || header->count == 0 || index >= header->count) return NULL;
size_t table_size = (size_t)header->count * sizeof(sv_map_template_desc_t); const sv_map_template_desc_t *table = (const sv_map_template_desc_t *)(const void *)( (const uint8_t *)header - table_size); const sv_map_template_desc_t *desc = &table[index]; if (desc->substitution_count == 0 || desc->substitution_count > SV_MAP_TEMPLATE_MAX_SUBSTITUTIONS || desc->operation > SV_MAP_TEMPLATE_HAS) return NULL;
for (uint8_t i = 0; i <= desc->substitution_count; i++) if (desc->segments[i].len > 0 && !desc->segments[i].str) return NULL; return desc;}
static inline sv_obj_site_cache_t *sv_obj_site_for_offset( sv_func_t *func, uint32_t bc_off) { if (!func || !func->obj_sites || func->obj_site_count == 0) return NULL;
uint32_t lo = 0; uint32_t hi = func->obj_site_count; while (lo < hi) { uint32_t mid = lo + (hi - lo) / 2; uint32_t site_off = func->obj_sites[mid].bc_off; if (site_off < bc_off) lo = mid + 1; else hi = mid; } if (lo >= func->obj_site_count || func->obj_sites[lo].bc_off != bc_off) return NULL; return &func->obj_sites[lo];}
static inline sv_func_metadata_t *sv_func_metadata(sv_func_t *func) { if (!func || !func->has_dynamic_eval) return NULL; ANT_ASSERT( func->type_data.metadata != NULL, "dynamic-eval function must have metadata" ); return func->type_data.metadata;}
static inline sv_type_info_t *sv_func_local_types(sv_func_t *func) { if (!func) return NULL; if (!func->has_dynamic_eval) return func->type_data.local_types; sv_func_metadata_t *metadata = sv_func_metadata(func); return metadata ? metadata->local_types : NULL;}
static inline const sv_eval_scope_t *sv_func_eval_scope(sv_func_t *func, uint32_t index) { sv_func_metadata_t *metadata = sv_func_metadata(func); ANT_ASSERT(metadata != NULL, "eval opcode requires function metadata"); ANT_ASSERT( index < metadata->eval_scope_count, "eval opcode scope index is outside function metadata" ); return &metadata->eval_scopes[index];}
typedef enum { SV_COMPLETION_NONE = 0, SV_COMPLETION_THROW = 1, SV_COMPLETION_RETURN = 2, SV_COMPLETION_JUMP = 3,} sv_completion_kind_t;
typedef struct { sv_completion_kind_t kind; ant_value_t value; uint8_t *jump_ip; uint16_t jump_finallies; uint16_t jump_pops;} sv_completion_t;
typedef enum { SV_RESUME_NEXT = 0, SV_RESUME_THROW = 1, SV_RESUME_RETURN = 2,} sv_resume_kind_t;
typedef struct sv_frame { uint8_t *ip; ant_value_t *bp; ant_value_t *lp; sv_func_t *func; ant_value_t callee; ant_value_t this; ant_value_t new_target; ant_value_t super_val; int prev_sp; int argc; sv_completion_t completion; sv_upvalue_t **upvalues;
int upvalue_count; uint16_t handler_base; uint16_t handler_top; ant_value_t arguments_obj; ant_value_t eval_env;} sv_frame_t;
static inline ant_value_t sv_frame_eval_env(ant_t *js, const sv_frame_t *frame) { return frame && is_object_type(frame->eval_env) ? frame->eval_env : js->global;}
typedef enum { SV_HANDLER_TRY = 1, SV_HANDLER_FINALLY = 2, SV_HANDLER_TRY_FINALLY = 3,} sv_handler_kind_t;
typedef struct { uint8_t *ip; int saved_sp; uint8_t kind; sv_completion_t completion;} sv_handler_t;
struct sv_upvalue { ant_value_t *location; ant_value_t closed; struct sv_upvalue *next; uint64_t gc_epoch; uint8_t in_remember_set; uint8_t maps_arguments; uint8_t args_index; uint32_t args_owner;};
static_assert( sizeof(struct sv_upvalue) == 40, "arguments link fields must stay in the upvalue padding");
static_assert( offsetof(struct sv_upvalue, maps_arguments) == offsetof(struct sv_upvalue, in_remember_set) + 1, "upvalue flag bytes are read together as one u16");
typedef struct sv_activation { int frame_count; int stack_count; int handler_count; size_t capacity; sv_upvalue_t *open_upvalues; sv_frame_t *frames; ant_value_t *slots; sv_handler_t *handlers;} sv_activation_t;
sv_activation_t *sv_activation_capture( sv_vm_t *vm, int entry_fp, sv_activation_t *reuse);
bool sv_activation_install(sv_vm_t *vm, sv_activation_t *act);void sv_activation_seal(ant_t *js, sv_activation_t *act);void sv_activation_discard(sv_vm_t *vm, int entry_fp);bool sv_vm_reserve_handlers(sv_vm_t *vm, int extra);void sv_frame_push_try_handlers(sv_vm_t *vm, sv_frame_t *frame, sv_func_t *func, int off, int base_sp);void sv_try_table_free(const struct sv_try_table *table);
static inline void gc_upvalue_write_barrier(ant_t *js, sv_upvalue_t *uv, ant_value_t new_val) { if (uv->in_remember_set || uv->gc_epoch == 0) return; if (!is_tagged(new_val) || !gc_value_is_heap_ref(new_val)) return; if (uv->location == &uv->closed || gc_value_ref_is_young(new_val)) gc_remember_upvalue(js, uv);}
void js_arguments_upvalue_written(ant_t *js, sv_upvalue_t *uv, ant_value_t value);void js_arguments_link_upvalue(ant_t *js, sv_frame_t *frame, sv_upvalue_t *uv);
static inline uint16_t sv_upvalue_flags(const sv_upvalue_t *uv) { uint16_t flags; __builtin_memcpy(&flags, &uv->in_remember_set, sizeof(flags)); return flags;}
static inline void sv_upvalue_store(ant_t *js, sv_upvalue_t *uv, ant_value_t val) { *uv->location = val; uint16_t flags = sv_upvalue_flags(uv); if (__builtin_expect(flags == 0, 1)) gc_upvalue_write_barrier(js, uv, val); else if (flags != 1) { gc_upvalue_write_barrier(js, uv, val); js_arguments_upvalue_written(js, uv, val); }}
static inline void gc_upvalue_capture_barrier(ant_t *js, sv_upvalue_t *uv) { if (uv->in_remember_set || uv->gc_epoch == 0) return; ant_value_t value = *uv->location; if (gc_value_is_heap_ref(value) && gc_value_ref_is_young(value)) gc_remember_upvalue(js, uv);}
static inline sv_upvalue_t *js_upvalue_alloc(ant_t *js) { sv_upvalue_t *uv = (sv_upvalue_t *)fixed_arena_alloc_uninit(&js->upvalue_arena); if (uv) { memset(uv, 0, sizeof(*uv)); if (js->young_upvalue_len < js->young_upvalue_cap) js->young_upvalues[js->young_upvalue_len++] = uv; else gc_track_young_upvalue_slow(js, uv); } return uv;}
#define SV_CALL_HAS_BOUND_ARGS (1u << 0)#define SV_CALL_HAS_SUPER (1u << 1)#define SV_CALL_IS_ARROW (1u << 2)#define SV_CALL_IS_DEFAULT_CTOR (1u << 3)#define SV_CALL_BORROWED_UPVALS (1u << 4)#define SV_CALL_HAS_EVAL_ENV (1u << 5)#define SV_CALL_HAS_BOUND_THIS (1u << 6)#define SV_CALL_IS_UNCURRY (1u << 7)
static constexpr char SV_CLASS_CTOR_CALL_ERROR[] = "Class constructor cannot be invoked without 'new'";
#define SV_CLOSURE_INLINE_UPVALS 4
typedef struct sv_closure { uint32_t call_flags; int bound_argc; sv_func_t *func; sv_upvalue_t **upvalues; sv_upvalue_t *inline_upvals[SV_CLOSURE_INLINE_UPVALS]; ant_value_t bound_this; ant_value_t super_val; ant_value_t func_obj;
union { struct { ant_value_t *argv; ant_value_t args_arr; } bound; struct { const char *name; uint32_t len; } pending; } u;
ant_t *js; ant_value_t module_ctx; uint8_t in_remember_set; uint8_t generation; uint64_t gc_epoch;} sv_closure_t;
static inline bool sv_closure_has_lexical_this(const sv_closure_t *closure) { return closure->func->is_arrow || (closure->call_flags & SV_CALL_HAS_BOUND_THIS);}
static inline void js_closure_alloc_prepare(ant_t *js) { js->gc.closure_alloc++; if (js->young_closure_len >= js->young_closure_trigger) gc_pressure(js);}
static inline sv_closure_t *js_closure_alloc_finish(ant_t *js, sv_closure_t *c) { c->gc_epoch = gc_get_epoch(js); c->js = js; c->func_obj = 0; c->module_ctx = mkval(kTypeUndefined, 0); c->u.pending.name = NULL; c->u.pending.len = 0; c->in_remember_set = 0; c->generation = 0; if (js->young_closure_len < js->young_closure_cap) js->young_closures[js->young_closure_len++] = c; else gc_track_young_closure_slow(js, c); return c;}
static inline sv_closure_t *js_closure_alloc(ant_t *js) { js_closure_alloc_prepare(js); sv_closure_t *c = (sv_closure_t *)fixed_arena_alloc(&js->closure_arena); if (!c && gc_reclaim_arena(js, &js->closure_arena)) c = (sv_closure_t *)fixed_arena_alloc(&js->closure_arena); if (!c) return NULL; return js_closure_alloc_finish(js, c);}
static inline sv_closure_t *js_closure_alloc_hot(ant_t *js) { js_closure_alloc_prepare(js); sv_closure_t *c = (sv_closure_t *)fixed_arena_alloc_uninit(&js->closure_arena); if (!c && gc_reclaim_arena(js, &js->closure_arena)) c = (sv_closure_t *)fixed_arena_alloc_uninit(&js->closure_arena); if (!c) return NULL; c->call_flags = 0; c->upvalues = NULL; return js_closure_alloc_finish(js, c);}
static inline sv_closure_t *js_func_closure(ant_value_t func) { return (sv_closure_t *)vptr(func);}
ant_value_t sv_string_builder_read_value(ant_t *js, ant_value_t value);ant_value_t sv_async_entry_finish(sv_vm_t *vm, int entry_fp, ant_value_t result);ant_value_t sv_closure_materialize_func_obj(ant_t *js, sv_closure_t *c, ant_value_t func_val);
static inline ant_value_t js_func_obj(ant_value_t func) { sv_closure_t *c = js_func_closure(func); if (__builtin_expect(c->func_obj == 0, 0)) return sv_closure_materialize_func_obj(c->js, c, func); return c->func_obj;}
static inline ant_value_t sv_closure_eval_env(const sv_closure_t *closure) { if (!closure || !(closure->call_flags & SV_CALL_HAS_EVAL_ENV) || !is_object_type(closure->func_obj)) return js_mkundef(); ant_value_t env = js_get_slot(closure->func_obj, SLOT_EVAL_ENV); return is_object_type(env) ? env : js_mkundef();}
static inline ant_value_t js_as_obj(ant_value_t v) { uint8_t t = vtype(v); if (t == kTypeObject) return v; if (t == kTypeFunction) return js_func_obj(v); return mkval(kTypeObject, vdata(v));}
ant_value_t sv_execute_closure_entry( sv_vm_t *vm,sv_closure_t *closure, ant_value_t callee_func, ant_value_t super_val, ant_value_t new_target, ant_value_t this_val, ant_value_t *args, int argc, ant_value_t *out_this);
ant_value_t sv_async_call_lazy( sv_vm_t *vm, sv_closure_t *closure, ant_value_t callee_func, ant_value_t super_val, ant_value_t this_val, ant_value_t *args, int argc, uint8_t next_op);
ant_value_t sv_execute_eval_entry( sv_vm_t *vm, sv_func_t *func, ant_value_t this_val, ant_value_t eval_env, ant_value_t new_target);
enum: uint8_t { SV_JIT_OSR_NONE = 0, SV_JIT_OSR_LOOP = 1, SV_JIT_OSR_AWAIT = 2,};
typedef struct { uint8_t active; int bc_offset; ant_value_t *locals; int n_locals; ant_value_t *lp; ant_value_t *vstack; int vstack_sp;} sv_jit_osr_t;
#define SV_TRY_MAX 64#define SV_TDZ T_EMPTY
#define SV_HANDLER_INITIAL (SV_TRY_MAX * 2)#define SV_HANDLER_HARD_MAX UINT16_MAX
#ifdef ANT_WASM_EMBED#define SV_FRAMES_HARD_MAX 16384#define SV_STACK_HARD_MAX 131072#else#define SV_FRAMES_HARD_MAX 65536#define SV_STACK_HARD_MAX 524288#endif
typedef struct sv_native_frame { struct sv_native_frame *caller; ant_value_t new_target;} sv_native_frame_t;
typedef struct sv_jit_osr_mark { struct sv_jit_osr_mark *prev;} sv_jit_osr_mark_t;
typedef struct { uint32_t bc_off; uint32_t live_start; uint16_t live_count; bool resumable; bool in_try;} sv_jit_await_site_t;
typedef struct sv_jit_await_map { int site_count; sv_jit_await_site_t *sites; uint16_t *live;} sv_jit_await_map_t;
typedef struct { uint32_t try_off; uint32_t pop_off; uint32_t catch_off; int32_t depth;} sv_try_region_t;
typedef struct sv_try_table { int *map; int *depth; int count; sv_try_region_t regions[];} sv_try_table_t;
static inline int sv_jit_await_site_index(const sv_jit_await_map_t *map, uint32_t bc_off) { int lo = 0, hi = map->site_count - 1; while (lo <= hi) { int mid = (lo + hi) / 2; if (map->sites[mid].bc_off < bc_off) lo = mid + 1; else if (map->sites[mid].bc_off > bc_off) hi = mid - 1; else return mid; } return -1;}
typedef struct sv_async_inline { int fp; bool entry; uint8_t next_op; struct coroutine *coro;} sv_async_inline_t;
struct sv_vm { ant_t *js;
ant_value_t *stack; int sp; int stack_size;
sv_frame_t *frames; int fp; int max_frames;
sv_upvalue_t *open_upvalues;
struct { sv_jit_osr_t osr; bool async_direct; uint8_t async_next_op; bool async_settled; bool mode_strict; int mode_fp; sv_jit_osr_mark_t *osr_marks; struct { bool active; int ip_offset; int n_params; int n_locals; int vstack_sp; ant_value_t *params; ant_value_t *locals; ant_value_t *vstack; } resume; } jit;
sv_handler_t *handler_stack; int handler_depth; int handler_cap;
struct { bool active; bool pending; bool is_error; sv_resume_kind_t kind; int entry_fp; int saved_fp; ant_value_t value; } suspend;
sv_native_frame_t *native_frame;
struct { sv_async_inline_t *records; int len; int cap; bool deferred; } async_inline;};
static_assert( offsetof(struct sv_vm, jit.async_next_op) < 4096, "fields read by compiled-code entry stubs need short immediate offsets");
int sv_async_entry_begin(sv_vm_t *vm, uint8_t next_op);
static inline uint8_t sv_get_u8(const uint8_t *ip) { return ip[0]; }static inline int8_t sv_get_i8(const uint8_t *ip) { return (int8_t)ip[0]; }
static inline uint16_t sv_get_u16(const uint8_t *ip) { uint16_t v; memcpy(&v, ip, 2); return v;}
static inline uint32_t sv_get_u32(const uint8_t *ip) { uint32_t v; memcpy(&v, ip, 4); return v;}
static inline int32_t sv_get_i32(const uint8_t *ip) { int32_t v; memcpy(&v, ip, 4); return v;}
static inline bool sv_frame_is_strict(const sv_frame_t *frame) { return frame && frame->func && frame->func->is_strict;}
static inline bool sv_slot_in_range( const ant_value_t *base, size_t count, const ant_value_t *slot) { if (!base || !slot || count == 0) return false;
uintptr_t lo = (uintptr_t)base; uintptr_t hi = lo + count * sizeof(*base); uintptr_t addr = (uintptr_t)slot; return addr >= lo && addr < hi;}
static inline bool sv_slot_in_vm_stack(const sv_vm_t *vm, const ant_value_t *slot) { return vm && sv_slot_in_range(vm->stack, (size_t)vm->stack_size, slot);}
static inline bool sv_is_nullish_this(ant_value_t v) { return vtype(v) == kTypeUndefined || vtype(v) == kTypeNull || (vtype(v) == kTypeObject && vdata(v) == 0);}
static inline ant_value_t sv_normalize_this_for_frame(ant_t *js, sv_func_t *func, ant_value_t this_val) { if (!func || func->is_arrow) return this_val; if (func->is_strict) return this_val; uint8_t type = vtype(this_val); if (type == kTypeUndefined || type == kTypeNull) return js->global_this; if (is_object_type(this_val) || type == kTypeBuiltin) return this_val; return js_normalize_sloppy_this(js, this_val);}
static inline bool sv_vm_is_strict(const sv_vm_t *vm) { if (vm && vm->jit.mode_fp == vm->fp) return vm->jit.mode_strict; if (vm && vm->fp >= 0) { const sv_frame_t *f = &vm->frames[vm->fp]; return f->func && f->func->is_strict; } return false;}
static inline bool sv_is_strict_context(ant_t *js) { return sv_vm_is_strict(js->vm);}
static inline ant_value_t sv_vm_get_new_target(const sv_vm_t *vm) { if (vm && vm->fp >= 0) return vm->frames[vm->fp].new_target; return js_mkundef();}
static inline ant_value_t sv_vm_get_super_val(const sv_vm_t *vm) { if (vm && vm->fp >= 0) return vm->frames[vm->fp].super_val; return js_mkundef();}
static inline int sv_frame_arg_slots(const sv_frame_t *frame) { if (!frame || !frame->func) return 0; return frame->argc > frame->func->param_count ? frame->argc : frame->func->param_count;}
static inline ant_value_t sv_frame_get_arg_value(const sv_frame_t *frame, uint16_t idx) { int arg_slots = sv_frame_arg_slots(frame); if (!frame || !frame->bp || (int)idx >= arg_slots) return js_mkundef(); return frame->bp[idx];}
static inline void sv_frame_set_arg_value(ant_t *js, sv_frame_t *frame, uint16_t idx, ant_value_t val) { int arg_slots = sv_frame_arg_slots(frame); if (!frame || !frame->bp || (int)idx >= arg_slots) return; frame->bp[idx] = val; if (vtype(frame->arguments_obj) != kTypeUndefined) js_arguments_sync_slot(js, frame->arguments_obj, idx, val);}
static inline ant_value_t *sv_frame_slot_ptr(sv_frame_t *frame, uint16_t slot_idx) { if (!frame || !frame->func) return NULL; int param_count = frame->func->param_count; if ((int)slot_idx < param_count) { int arg_slots = sv_frame_arg_slots(frame); if ((int)slot_idx >= arg_slots || !frame->bp) return NULL; return &frame->bp[slot_idx]; } if (!frame->lp) return NULL; return &frame->lp[slot_idx - param_count];}
ant_value_t sv_string_builder_flush_slot( sv_vm_t *vm, ant_t *js, sv_frame_t *frame, uint16_t slot_idx);
ant_value_t sv_string_builder_append_slot( sv_vm_t *vm, ant_t *js, sv_frame_t *frame, sv_func_t *func, uint16_t slot_idx, ant_value_t rhs);
ant_value_t sv_string_builder_append_snapshot_slot( sv_vm_t *vm, ant_t *js, sv_frame_t *frame, sv_func_t *func, uint16_t slot_idx, ant_value_t lhs, ant_value_t rhs);
#endif