Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657#ifndef ANT_INTERNAL_H#define ANT_INTERNAL_H
#include "ant.h"#include "object.h"#include "pool.h"#include "sugar.h"#include "errors.h"#include "arena.h"#include "descriptors.h"#include "esm/loader.h"
#include <assert.h>#include <string.h>
// An IEEE 754 double-precision float is a 64-bit value with bits laid out like://// 1 Sign bit// | 11 Exponent bits// | | 52 Mantissa (i.e. fraction) bits// | | |// S[Exponent-][Mantissa------------------------------------------]//// A NaN is any value where all exponent bits are set and the mantissa is// non-zero. That means there are a *lot* of bit patterns that all represent// NaN. NaN tagging takes advantage of this by repurposing those unused// patterns to encode non-numeric values.//// We define a NANBOX_PREFIX as the upper 12 bits all set (0xFFF0...)://// 1111 1111 1111 0000 0000 0000 ... 0000// [sign+exp all 1s ] [mantissa all 0s ]//// This corresponds to -Infinity in IEEE 754. Any 64-bit value strictly// greater than this prefix is a tagged (non-numeric) value. Any value less// than or equal to it is an unmodified double — so numeric math is free.//// For tagged values, we carve the remaining 52 mantissa bits into two fields://// 1111 1111 1111 TTTTT DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD// [-- prefix ---][type][--------------- 47-bit data --------------------]//// The 5-bit type tag (bits 51–47) encodes up to 31 distinct types: objects,// strings, booleans, undefined, null, functions, closures, errors, etc.// The 47-bit data field holds either a heap offset (for heap-resident types// like objects and strings) or an immediate value (e.g. 1 for true, 0 for// false).//// Encoding and decoding are simple://// mkval(type, data) = PREFIX | (type << 47) | (data & 0x7FFFFFFFFFFF)// vtype(v) = is_tagged(v) ? (v >> 47) & 0x1F : T_NUM// vdata(v) = v & 0x7FFFFFFFFFFF// is_tagged(v) = v > PREFIX
#define NANBOX_TYPE_MASK 0x1F#define NANBOX_TYPE_SHIFT 0x2F#define NANBOX_HEAP_OFFSET 0x8#define NANBOX_PREFIX 0xFFF0000000000000ULL#define NANBOX_DATA_MASK 0x00007FFFFFFFFFFFULL
#define JS_ERR_NO_STACK (1 << 8)#define JS_TPFLG(t) (1u << (t))
#define MAX_STRINGIFY_DEPTH 64#define MAX_PROTO_CHAIN_DEPTH 256#define MAX_MULTIREF_OBJS 128#define MAX_DENSE_INITIAL_CAP 8
#define PROTO_WALK_F_OBJECT_ONLY (1u << 0)#define PROTO_WALK_F_LOOKUP (1u << 1)
#define ROPE_MAX_DEPTH 4096#define ROPE_FLATTEN_THRESHOLD (512 * 1024)
#define STR_BUILDER_TAIL_CAP 256u#define STR_HEAP_TAG_MASK 0x3ULL#define STR_HEAP_TAG_FLAT 0x0ULL#define STR_HEAP_TAG_ROPE 0x1ULL#define STR_HEAP_TAG_BUILDER 0x2ULL
#define T_EMPTY (NANBOX_PREFIX | ((ant_value_t)T_SENTINEL << NANBOX_TYPE_SHIFT) | 0xDEADULL)#define T_SPECIAL_OBJECT_MASK (JS_TPFLG(T_OBJ) | JS_TPFLG(T_ARR))#define T_NEEDS_PROTO_FALLBACK (JS_TPFLG(T_FUNC) | JS_TPFLG(T_ARR) | JS_TPFLG(T_PROMISE) | JS_TPFLG(T_GENERATOR))#define T_OBJECT_MASK (JS_TPFLG(T_OBJ) | JS_TPFLG(T_ARR) | JS_TPFLG(T_FUNC) | JS_TPFLG(T_PROMISE) | JS_TPFLG(T_GENERATOR))#define T_NON_NUMERIC_MASK (JS_TPFLG(T_STR) | JS_TPFLG(T_ARR) | JS_TPFLG(T_FUNC) | JS_TPFLG(T_CFUNC) | JS_TPFLG(T_OBJ) | JS_TPFLG(T_GENERATOR))
#define is_non_numeric(v) ((1u << vtype(v)) & T_NON_NUMERIC_MASK)#define is_object_type(v) ((1u << vtype(v)) & T_OBJECT_MASK)#define is_special_object(v) ((1u << vtype(v)) & T_SPECIAL_OBJECT_MASK)
enum { // heap-resident T_OBJ = 0, T_STR = 1, T_ARR = 2,
// objects T_FUNC, T_CFUNC, T_PROMISE, T_GENERATOR,
// primitives T_UNDEF, T_NULL, T_BOOL, T_NUM, T_BIGINT, T_SYMBOL,
// internal T_ERR, T_TYPEDARRAY, T_NTARG,
// collections T_MAP, T_SET, T_WEAKMAP, T_WEAKSET,
T_SENTINEL = NANBOX_TYPE_MASK};
typedef struct { const char *src; const char *filename; ant_offset_t src_len; ant_offset_t off; ant_offset_t span_len; bool valid;} js_error_site_t;
struct ant_isolate_t { sv_vm_t *vm; ant_module_t *module; ant_object_t *objects; ant_object_t *permanent_objects; ant_fixed_arena_t obj_arena; ant_prop_ref_t *prop_refs;
ant_fixed_arena_t closure_arena; ant_fixed_arena_t upvalue_arena; ant_value_t **c_roots; size_t c_root_count; size_t c_root_cap; struct gc_temp_root_scope *temp_roots;
const char *code; const char *filename;
#ifdef ANT_JIT void *jit_ctx; #endif ant_value_t global; ant_value_t this_val; ant_value_t new_target; ant_value_t current_func; ant_value_t length_str; struct { const char *length; const char *buffer; const char *prototype; const char *constructor; const char *name; const char *message; const char *done; const char *value; const char *get; const char *set; const char *arguments; const char *callee; const char *idx[10]; } intern; ant_value_t thrown_value; ant_value_t thrown_stack;
struct { void *base; void *main_base; void *main_lo; size_t limit; } cstk;
struct { uint64_t counter; struct sym_registry_entry *registry; ant_value_t object_proto; ant_value_t array_proto; ant_value_t iterator_proto; ant_value_t array_iterator_proto; ant_value_t string_iterator_proto; ant_value_t generator_proto; ant_value_t async_generator_proto; ant_value_t async_iterator_proto; } sym; ant_offset_t max_size; ant_offset_t prop_refs_len; ant_offset_t prop_refs_cap; js_error_site_t errsite;
struct { ant_pool_t rope; ant_pool_t symbol; ant_pool_t permanent; ant_class_pool_t bigint; ant_string_pool_t string; } pool;
struct { size_t closures; size_t upvalues; } alloc_bytes; size_t gc_last_live; size_t gc_pool_alloc; size_t gc_pool_last_live;
ant_object_t *objects_old; size_t old_live_count; size_t minor_gc_count;
ant_object_t **remember_set; size_t remember_set_len; size_t remember_set_cap;
#ifdef ANT_JIT uint32_t jit_active_depth; #endif
uint32_t vm_exec_depth; bool microtasks_draining; struct coroutine *active_async_coro;
struct { ant_value_t *items; size_t len; size_t cap; } pending_rejections;
struct { uintptr_t *cfunc_ptr; ant_value_t *promoted; uint8_t len; uint8_t cap; } cfunc_promote_cache;
struct { const ant_cfunc_meta_t **base_meta; const char **name_ptr; ant_value_t *named; uint16_t len; uint16_t cap; } cfunc_name_cache;
bool owns_mem; bool fatal_error; bool thrown_exists;};
enum { STR_ASCII_UNKNOWN = 0, STR_ASCII_YES = 1, STR_ASCII_NO = 2,};
typedef struct { ant_offset_t len; uint8_t is_ascii; char bytes[];} ant_flat_string_t;
typedef struct ant_builder_chunk { struct ant_builder_chunk *next; ant_value_t value;} ant_builder_chunk_t;
typedef struct { ant_offset_t len; ant_builder_chunk_t *head; ant_builder_chunk_t *chunk_tail; ant_value_t cached; uint16_t tail_len; uint8_t ascii_state; char tail[STR_BUILDER_TAIL_CAP];} ant_string_builder_t;
typedef struct { const char *ptr; size_t len; bool needs_free;} js_cstr_t;
typedef struct { size_t count; size_t bytes;} js_intern_stats_t;
typedef struct { bool has_getter; bool has_setter; bool writable; bool enumerable; bool configurable; ant_value_t getter; ant_value_t setter;} prop_meta_t;
typedef enum { PROP_META_STRING = 0, PROP_META_SYMBOL = 1,} prop_meta_key_t;
static inline bool is_err(ant_value_t v) { return vtype(v) == T_ERR; }
static inline bool is_null(ant_value_t v) { return vtype(v) == T_NULL; }
static inline bool is_undefined(ant_value_t v) { return vtype(v) == T_UNDEF; }
static inline bool is_empty_slot(ant_value_t v) { return v == T_EMPTY; }
static inline bool is_callable(ant_value_t v) { uint8_t t = vtype(v); return t == T_FUNC || t == T_CFUNC;}
static inline const ant_cfunc_meta_t *js_as_cfunc_meta(ant_value_t fn_val) { return (const ant_cfunc_meta_t *)(uintptr_t)vdata(fn_val);}
static inline ant_cfunc_t js_as_cfunc(ant_value_t fn_val) { const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); return meta ? meta->fn : NULL;}
static inline uint32_t js_cfunc_length(ant_value_t fn_val) { const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); return meta ? meta->length : 0;}
static inline bool js_cfunc_same_entrypoint(ant_value_t fn_val, ant_cfunc_t fn) { const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); return meta && meta->fn == fn;}
size_t uint_to_str(char *buf, size_t bufsize, uint64_t val);int extract_array_args(ant_t *js, ant_value_t arr, ant_value_t **out_args);
ant_value_t tov(double d);double tod(ant_value_t v);double js_to_number(ant_t *js, ant_value_t arg);
bool js_obj_ensure_prop_capacity(ant_object_t *obj, uint32_t needed);bool js_obj_ensure_unique_shape(ant_object_t *obj);
ant_value_t js_propref_load(ant_t *js, ant_offset_t handle);ant_value_t mkprop(ant_t *js, ant_value_t obj, ant_value_t k, ant_value_t v, uint8_t attrs);ant_value_t mkprop_interned(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs);ant_value_t mkprop_interned_exact(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs);ant_value_t setprop_cstr(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v);ant_value_t setprop_interned(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v);ant_value_t js_define_property(ant_t *js, ant_value_t obj, ant_value_t prop, ant_value_t descriptor, bool reflect_mode);
// TODO: move into builder.ctypedef struct { ant_t *js; char *buf; size_t len; size_t n; bool growable; bool inline_mode; bool first; bool closed; bool did_indent;} js_inspect_builder_t;
void js_inspect_builder_init_fixed(js_inspect_builder_t *builder, ant_t *js, char *buf, size_t len, size_t initial_n);bool js_inspect_builder_init_dynamic(js_inspect_builder_t *builder, ant_t *js, size_t initial_cap);void js_inspect_builder_dispose(js_inspect_builder_t *builder);bool js_inspect_tagged_header(js_inspect_builder_t *builder, const char *tag, size_t tag_len);bool js_inspect_object_body(js_inspect_builder_t *builder, ant_value_t obj);bool js_inspect_close(js_inspect_builder_t *builder);
__attribute__((format(printf, 2, 3)))bool js_inspect_header(js_inspect_builder_t *builder, const char *fmt, ...);
__attribute__((format(printf, 3, 4)))bool js_inspect_header_for(js_inspect_builder_t *builder, ant_value_t obj, const char *fmt, ...);
ant_value_t js_inspect_builder_result(js_inspect_builder_t *builder);ant_value_t js_define_own_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t v);ant_value_t js_instance_proto_from_new_target(ant_t *js, ant_value_t fallback_proto);
ant_value_t js_get_module_import_binding(ant_t *js);ant_value_t js_builtin_import(ant_t *js, ant_value_t *args, int nargs);ant_value_t js_create_import_meta(ant_t *js, const char *filename, bool is_main);ant_value_t js_create_module_context(ant_t *js, const char *filename, bool is_main);ant_value_t js_create_arguments_object(ant_t *js, ant_value_t callee, sv_frame_t *frame, int argc, int mapped_count, bool is_strict);
void js_arguments_detach(ant_t *js, ant_value_t obj);void js_arguments_sync_slot(ant_t *js, ant_value_t obj, uint32_t idx, ant_value_t value);
ant_value_t coerce_to_str(ant_t *js, ant_value_t v);ant_value_t coerce_to_str_concat(ant_t *js, ant_value_t v);ant_value_t get_ctor_species_value(ant_t *js, ant_value_t ctor);
bool proto_chain_contains(ant_t *js, ant_value_t obj, ant_value_t proto_target);bool same_ctor_identity(ant_t *js, ant_value_t a, ant_value_t b);
js_intern_stats_t js_intern_stats(void);const char *intern_string(const char *str, size_t len);js_cstr_t js_to_cstr(ant_t *js, ant_value_t value, char *stack_buf, size_t stack_size);
ant_value_t lkp_interned_val(ant_t *js, ant_value_t obj, const char *search_intern);ant_offset_t lkp_interned(ant_t *js, ant_value_t obj, const char *search_intern, size_t len);
ant_offset_t lkp(ant_t *js, ant_value_t obj, const char *buf, size_t len);ant_offset_t lkp_proto(ant_t *js, ant_value_t obj, const char *buf, size_t len);
ant_offset_t lkp_sym(ant_t *js, ant_value_t obj, ant_offset_t sym_off);ant_offset_t lkp_sym_proto(ant_t *js, ant_value_t obj, ant_offset_t sym_off);
ant_offset_t vstr(ant_t *js, ant_value_t value, ant_offset_t *len);ant_offset_t vstrlen(ant_t *js, ant_value_t value);ant_offset_t str_len_fast(ant_t *js, ant_value_t str);
ant_value_t mkval(uint8_t type, uint64_t data);ant_value_t mkobj(ant_t *js, ant_offset_t parent);ant_value_t js_mkobj_with_inobj_limit(ant_t *js, uint8_t inobj_limit);ant_value_t rope_flatten(ant_t *js, ant_value_t rope);ant_value_t str_materialize(ant_t *js, ant_value_t value);
ant_value_t js_for_in_keys(ant_t *js, ant_value_t obj);ant_value_t js_delete_prop(ant_t *js, ant_value_t obj, const char *key, size_t len);ant_value_t js_delete_sym_prop(ant_t *js, ant_value_t obj, ant_value_t sym);
bool is_proxy(ant_value_t obj);bool strict_eq_values(ant_t *js, ant_value_t l, ant_value_t r);bool js_deep_equal(ant_t *js, ant_value_t a, ant_value_t b, bool strict);
ant_value_t js_proxy_apply(ant_t *js, ant_value_t proxy, ant_value_t this_arg, ant_value_t *args, int argc);ant_value_t js_proxy_construct(ant_t *js, ant_value_t proxy, ant_value_t *args, int argc, ant_value_t new_target);ant_value_t sv_call_native(ant_t *js, ant_value_t func, ant_value_t this_val, ant_value_t *args, int nargs);
const char *typestr(uint8_t t);ant_value_t unwrap_primitive(ant_t *js, ant_value_t val);ant_value_t do_string_op(ant_t *js, uint8_t op, ant_value_t l, ant_value_t r);ant_value_t js_to_primitive(ant_t *js, ant_value_t value, int hint);
ant_value_t do_instanceof(ant_t *js, ant_value_t l, ant_value_t r);ant_value_t do_in(ant_t *js, ant_value_t l, ant_value_t r);
bool js_is_prototype_of(ant_t *js, ant_value_t proto_obj, ant_value_t obj);ant_value_t builtin_object_isPrototypeOf(ant_t *js, ant_value_t *args, int nargs);ant_value_t builtin_object_freeze(ant_t *js, ant_value_t *args, int nargs);
bool js_is_array_includes_builtin(ant_value_t func);ant_value_t js_array_includes_call(ant_t *js, ant_value_t this_val, ant_value_t *args, int nargs);ant_value_t builtin_array_includes(ant_t *js, ant_value_t *args, int nargs);
void js_module_eval_ctx_push(ant_t *js, ant_module_t *ctx);void js_module_eval_ctx_pop(ant_t *js, ant_module_t *ctx);
bool lookup_prop_meta( ant_t *js, ant_value_t cur_obj, prop_meta_key_t key_kind, const char *key, size_t klen, ant_offset_t sym_off, prop_meta_t *out);
static inline ant_value_t js_module_eval_active_ns(ant_t *js) { ant_module_t *ctx = js->module; return ctx ? ctx->module_ns : js_mkundef();}
static inline ant_value_t js_module_eval_active_ctx(ant_t *js) { ant_module_t *ctx = js->module; return ctx ? ctx->module_ctx : js_mkundef();}
static inline ant_value_t js_module_eval_active_import_meta(ant_t *js) { ant_value_t module_ctx = js_module_eval_active_ctx(js); return is_object_type(module_ctx) ? js_get(js, module_ctx, "meta") : js_mkundef();}
static inline const char *js_module_eval_active_filename(ant_t *js) { ant_value_t module_ctx = js_module_eval_active_ctx(js); if (is_object_type(module_ctx)) { ant_value_t filename = js_get(js, module_ctx, "filename"); if (vtype(filename) == T_STR) return js_getstr(js, filename, NULL); } return js->filename;}
static inline ant_module_format_t js_module_eval_active_format(ant_t *js) { ant_module_t *ctx = js->module; return ctx ? ctx->format : MODULE_EVAL_FORMAT_UNKNOWN;}
static inline bool is_length_key(const char *key, size_t len) { return len == 6 && !memcmp(key, "length", 6);}
// TODO: move strings helpers to strings.hstatic inline bool str_is_heap_rope(ant_value_t value) { return vtype(value) == T_STR && ((vdata(value) & STR_HEAP_TAG_MASK) == STR_HEAP_TAG_ROPE);}
static inline bool str_is_heap_builder(ant_value_t value) { return vtype(value) == T_STR && ((vdata(value) & STR_HEAP_TAG_MASK) == STR_HEAP_TAG_BUILDER);}
static inline ant_rope_heap_t *ant_str_rope_ptr(ant_value_t value) { return (ant_rope_heap_t *)(uintptr_t)(vdata(value) & ~STR_HEAP_TAG_MASK);}
static inline ant_string_builder_t *ant_str_builder_ptr(ant_value_t value) { return (ant_string_builder_t *)(uintptr_t)(vdata(value) & ~STR_HEAP_TAG_MASK);}
static inline ant_value_t ant_mkrope_value(ant_rope_heap_t *rope) { return mkval(T_STR, ((uintptr_t)rope) | STR_HEAP_TAG_ROPE);}
static inline ant_value_t ant_mkbuilder_value(ant_string_builder_t *builder) { return mkval(T_STR, ((uintptr_t)builder) | STR_HEAP_TAG_BUILDER);}
static inline int js_brand_id(ant_value_t obj) { if (!is_object_type(obj)) return BRAND_NONE; ant_value_t brand = js_get_slot(obj, SLOT_BRAND); return vtype(brand) == T_NUM ? (int)js_getnum(brand) : BRAND_NONE;}
static inline bool js_check_brand(ant_value_t obj, int brand) { return js_brand_id(obj) == brand;}
static inline bool lookup_symbol_prop_meta(ant_value_t cur_obj, ant_offset_t sym_off, prop_meta_t *out) { return lookup_prop_meta(NULL, cur_obj, PROP_META_SYMBOL, NULL, 0, sym_off, out);}
static inline bool lookup_string_prop_meta(ant_t *js, ant_value_t cur_obj, const char *key, size_t klen, prop_meta_t *out) { return lookup_prop_meta(js, cur_obj, PROP_META_STRING, key, klen, 0, out);}
static inline ant_value_t defmethod(ant_t *js, ant_value_t obj, const char *name, size_t len, ant_value_t fn) { const char *interned = intern_string(name, len); if (!interned) return js_mkerr(js, "oom"); return mkprop_interned( js, obj, interned, fn, ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE );}
static inline ant_value_t defalias(ant_t *js, ant_value_t obj, const char *name, size_t len, ant_value_t fn) { const char *interned = intern_string(name, len); if (!interned) return js_mkerr(js, "oom");
return mkprop_interned_exact( js, obj, interned, fn, ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE );}
static inline ant_flat_string_t *str_flat_from_bytes(const char *str) { return (ant_flat_string_t *)((char *)str - offsetof(ant_flat_string_t, bytes));}
static inline ant_flat_string_t *ant_str_flat_ptr(ant_value_t value) { if (vtype(value) != T_STR) return NULL; if ((vdata(value) & STR_HEAP_TAG_MASK) != STR_HEAP_TAG_FLAT) return NULL; return (ant_flat_string_t *)(uintptr_t)vdata(value);}
static inline ant_flat_string_t *large_string_flat_ptr(ant_large_string_alloc_t *alloc) { return alloc ? (ant_flat_string_t *)&alloc->len : NULL;}
static inline ant_large_string_alloc_t *large_string_alloc_from_flat(ant_flat_string_t *flat) { return flat ? (ant_large_string_alloc_t *)((char *)flat - offsetof(ant_large_string_alloc_t, len)) : NULL;}
static inline uint8_t str_detect_ascii_bytes(const char *str, size_t len) { const unsigned char *s = (const unsigned char *)str; for (size_t i = 0; i < len; i++) { if (s[i] >= 0x80) return STR_ASCII_NO; } return STR_ASCII_YES;}
static inline void str_set_ascii_state(const char *str, uint8_t state) { ant_flat_string_t *flat = str_flat_from_bytes(str); flat->is_ascii = state;}
static inline bool str_is_ascii(const char *str) { ant_flat_string_t *flat = str_flat_from_bytes(str); if (flat->is_ascii == STR_ASCII_UNKNOWN) { flat->is_ascii = str_detect_ascii_bytes(flat->bytes, (size_t)flat->len); } return flat->is_ascii == STR_ASCII_YES;}
static inline void js_set_module_default(ant_t *js, ant_value_t lib, ant_value_t ctor_fn, const char *name) { js_set(js, ctor_fn, name, ctor_fn); js_set(js, lib, name, ctor_fn); js_set(js, lib, "default", ctor_fn); js_set(js, ctor_fn, "default", ctor_fn); js_set_slot_wb(js, lib, SLOT_DEFAULT, ctor_fn);}
ant_value_t js_cfunc_promote(ant_t *js, ant_value_t cfunc);ant_value_t js_cfunc_expose_named(ant_t *js, ant_value_t cfunc, const char *name, size_t name_len);
static inline ant_value_t js_cfunc_lookup_promoted(ant_t *js, ant_value_t cfunc) { uintptr_t ptr = vdata(cfunc); for (uint8_t i = 0; i < js->cfunc_promote_cache.len; i++) if ( js->cfunc_promote_cache.cfunc_ptr[i] == ptr ) return js->cfunc_promote_cache.promoted[i]; return cfunc;}
static inline ant_value_t js_make_ctor(ant_t *js, ant_cfunc_t fn, ant_value_t proto, const char *name, size_t nlen) { ant_value_t obj = js_mkobj(js); js_set_slot(obj, SLOT_CFUNC, js_mkfun_dyn(fn)); js_mkprop_fast(js, obj, "prototype", 9, proto); js_mkprop_fast(js, obj, "name", 4, js_mkstr(js, name, nlen)); js_set_descriptor(js, obj, "name", 4, 0);
ant_value_t fn_val = js_obj_to_func(obj); js_set(js, proto, "constructor", fn_val); js_set_descriptor(js, proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
return fn_val;}
#endif