MIRROR: javascript for 🐜's, a tiny runtime with big ambitions
1#ifndef ANT_INTERNAL_H
2#define ANT_INTERNAL_H
3
4#include "ant.h"
5#include "object.h"
6#include "pool.h"
7#include "sugar.h"
8#include "errors.h"
9#include "arena.h"
10#include "descriptors.h"
11#include "esm/loader.h"
12
13#include <assert.h>
14#include <string.h>
15
16// An IEEE 754 double-precision float is a 64-bit value with bits laid out like:
17//
18// 1 Sign bit
19// | 11 Exponent bits
20// | | 52 Mantissa (i.e. fraction) bits
21// | | |
22// S[Exponent-][Mantissa------------------------------------------]
23//
24// A NaN is any value where all exponent bits are set and the mantissa is
25// non-zero. That means there are a *lot* of bit patterns that all represent
26// NaN. NaN tagging takes advantage of this by repurposing those unused
27// patterns to encode non-numeric values.
28//
29// We define a NANBOX_PREFIX as the upper 12 bits all set (0xFFF0...):
30//
31// 1111 1111 1111 0000 0000 0000 ... 0000
32// [sign+exp all 1s ] [mantissa all 0s ]
33//
34// This corresponds to -Infinity in IEEE 754. Any 64-bit value strictly
35// greater than this prefix is a tagged (non-numeric) value. Any value less
36// than or equal to it is an unmodified double — so numeric math is free.
37//
38// For tagged values, we carve the remaining 52 mantissa bits into two fields:
39//
40// 1111 1111 1111 TTTTT DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
41// [-- prefix ---][type][--------------- 47-bit data --------------------]
42//
43// The 5-bit type tag (bits 51–47) encodes up to 31 distinct types: objects,
44// strings, booleans, undefined, null, functions, closures, errors, etc.
45// The 47-bit data field holds either a heap offset (for heap-resident types
46// like objects and strings) or an immediate value (e.g. 1 for true, 0 for
47// false).
48//
49// Encoding and decoding are simple:
50//
51// mkval(type, data) = PREFIX | (type << 47) | (data & 0x7FFFFFFFFFFF)
52// vtype(v) = is_tagged(v) ? (v >> 47) & 0x1F : T_NUM
53// vdata(v) = v & 0x7FFFFFFFFFFF
54// is_tagged(v) = v > PREFIX
55
56#define NANBOX_TYPE_MASK 0x1F
57#define NANBOX_TYPE_SHIFT 0x2F
58#define NANBOX_HEAP_OFFSET 0x8
59#define NANBOX_PREFIX 0xFFF0000000000000ULL
60#define NANBOX_DATA_MASK 0x00007FFFFFFFFFFFULL
61
62#define JS_ERR_NO_STACK (1 << 8)
63#define JS_TPFLG(t) (1u << (t))
64
65#define MAX_STRINGIFY_DEPTH 64
66#define MAX_PROTO_CHAIN_DEPTH 256
67#define MAX_MULTIREF_OBJS 128
68#define MAX_DENSE_INITIAL_CAP 8
69
70#define PROTO_WALK_F_OBJECT_ONLY (1u << 0)
71#define PROTO_WALK_F_LOOKUP (1u << 1)
72
73#define ROPE_MAX_DEPTH 4096
74#define ROPE_FLATTEN_THRESHOLD (512 * 1024)
75
76#define STR_BUILDER_TAIL_CAP 256u
77#define STR_HEAP_TAG_MASK 0x3ULL
78#define STR_HEAP_TAG_FLAT 0x0ULL
79#define STR_HEAP_TAG_ROPE 0x1ULL
80#define STR_HEAP_TAG_BUILDER 0x2ULL
81
82#define T_EMPTY (NANBOX_PREFIX | ((ant_value_t)T_SENTINEL << NANBOX_TYPE_SHIFT) | 0xDEADULL)
83#define T_SPECIAL_OBJECT_MASK (JS_TPFLG(T_OBJ) | JS_TPFLG(T_ARR))
84#define T_NEEDS_PROTO_FALLBACK (JS_TPFLG(T_FUNC) | JS_TPFLG(T_ARR) | JS_TPFLG(T_PROMISE) | JS_TPFLG(T_GENERATOR))
85#define T_OBJECT_MASK (JS_TPFLG(T_OBJ) | JS_TPFLG(T_ARR) | JS_TPFLG(T_FUNC) | JS_TPFLG(T_PROMISE) | JS_TPFLG(T_GENERATOR))
86#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))
87
88#define is_non_numeric(v) ((1u << vtype(v)) & T_NON_NUMERIC_MASK)
89#define is_object_type(v) ((1u << vtype(v)) & T_OBJECT_MASK)
90#define is_special_object(v) ((1u << vtype(v)) & T_SPECIAL_OBJECT_MASK)
91
92enum {
93 // heap-resident
94 T_OBJ = 0,
95 T_STR = 1,
96 T_ARR = 2,
97
98 // objects
99 T_FUNC,
100 T_CFUNC,
101 T_PROMISE,
102 T_GENERATOR,
103
104 // primitives
105 T_UNDEF,
106 T_NULL,
107 T_BOOL,
108 T_NUM,
109 T_BIGINT,
110 T_SYMBOL,
111
112 // internal
113 T_ERR,
114 T_TYPEDARRAY,
115 T_NTARG,
116
117 // collections
118 T_MAP,
119 T_SET,
120 T_WEAKMAP,
121 T_WEAKSET,
122
123 T_SENTINEL = NANBOX_TYPE_MASK
124};
125
126typedef struct {
127 const char *src;
128 const char *filename;
129 ant_offset_t src_len;
130 ant_offset_t off;
131 ant_offset_t span_len;
132 bool valid;
133} js_error_site_t;
134
135struct ant_isolate_t {
136 sv_vm_t *vm;
137
138 ant_module_t *module;
139 ant_object_t *objects;
140 ant_object_t *permanent_objects;
141
142 ant_fixed_arena_t obj_arena;
143 ant_prop_ref_t *prop_refs;
144
145 ant_fixed_arena_t closure_arena;
146 ant_fixed_arena_t upvalue_arena;
147
148 ant_value_t **c_roots;
149 size_t c_root_count;
150 size_t c_root_cap;
151 struct gc_temp_root_scope *temp_roots;
152
153 const char *code;
154 const char *filename;
155
156 #ifdef ANT_JIT
157 void *jit_ctx;
158 #endif
159
160 ant_value_t global;
161 ant_value_t this_val;
162 ant_value_t new_target;
163 ant_value_t current_func;
164 ant_value_t length_str;
165
166 struct {
167 const char *length;
168 const char *buffer;
169 const char *prototype;
170 const char *constructor;
171 const char *name;
172 const char *message;
173 const char *done;
174 const char *value;
175 const char *get;
176 const char *set;
177 const char *arguments;
178 const char *callee;
179 const char *idx[10];
180 } intern;
181
182 ant_value_t thrown_value;
183 ant_value_t thrown_stack;
184
185 struct {
186 void *base;
187 void *main_base;
188 void *main_lo;
189 size_t limit;
190 } cstk;
191
192 struct {
193 uint64_t counter;
194 struct sym_registry_entry *registry;
195
196 ant_value_t object_proto;
197 ant_value_t array_proto;
198 ant_value_t iterator_proto;
199 ant_value_t array_iterator_proto;
200 ant_value_t string_iterator_proto;
201 ant_value_t generator_proto;
202 ant_value_t async_generator_proto;
203 ant_value_t async_iterator_proto;
204 } sym;
205
206 ant_offset_t max_size;
207 ant_offset_t prop_refs_len;
208 ant_offset_t prop_refs_cap;
209 js_error_site_t errsite;
210
211 struct {
212 ant_pool_t rope;
213 ant_pool_t symbol;
214 ant_pool_t permanent;
215 ant_class_pool_t bigint;
216 ant_string_pool_t string;
217 } pool;
218
219 struct {
220 size_t closures;
221 size_t upvalues;
222 } alloc_bytes;
223
224 size_t gc_last_live;
225 size_t gc_pool_alloc;
226 size_t gc_pool_last_live;
227
228 ant_object_t *objects_old;
229 size_t old_live_count;
230 size_t minor_gc_count;
231
232 ant_object_t **remember_set;
233 size_t remember_set_len;
234 size_t remember_set_cap;
235
236 #ifdef ANT_JIT
237 uint32_t jit_active_depth;
238 #endif
239
240 uint32_t vm_exec_depth;
241 bool microtasks_draining;
242 struct coroutine *active_async_coro;
243
244 struct {
245 ant_value_t *items;
246 size_t len;
247 size_t cap;
248 } pending_rejections;
249
250 struct {
251 uintptr_t *cfunc_ptr;
252 ant_value_t *promoted;
253 uint8_t len;
254 uint8_t cap;
255 } cfunc_promote_cache;
256
257 struct {
258 const ant_cfunc_meta_t **base_meta;
259 const char **name_ptr;
260 ant_value_t *named;
261 uint16_t len;
262 uint16_t cap;
263 } cfunc_name_cache;
264
265 bool owns_mem;
266 bool fatal_error;
267 bool thrown_exists;
268};
269
270enum {
271 STR_ASCII_UNKNOWN = 0,
272 STR_ASCII_YES = 1,
273 STR_ASCII_NO = 2,
274};
275
276typedef struct {
277 ant_offset_t len;
278 uint8_t is_ascii;
279 char bytes[];
280} ant_flat_string_t;
281
282typedef struct ant_builder_chunk {
283 struct ant_builder_chunk *next;
284 ant_value_t value;
285} ant_builder_chunk_t;
286
287typedef struct {
288 ant_offset_t len;
289 ant_builder_chunk_t *head;
290 ant_builder_chunk_t *chunk_tail;
291 ant_value_t cached;
292 uint16_t tail_len;
293 uint8_t ascii_state;
294 char tail[STR_BUILDER_TAIL_CAP];
295} ant_string_builder_t;
296
297typedef struct {
298 const char *ptr;
299 size_t len;
300 bool needs_free;
301} js_cstr_t;
302
303typedef struct {
304 size_t count;
305 size_t bytes;
306} js_intern_stats_t;
307
308typedef struct {
309 bool has_getter;
310 bool has_setter;
311 bool writable;
312 bool enumerable;
313 bool configurable;
314 ant_value_t getter;
315 ant_value_t setter;
316} prop_meta_t;
317
318typedef enum {
319 PROP_META_STRING = 0,
320 PROP_META_SYMBOL = 1,
321} prop_meta_key_t;
322
323static inline bool is_err(ant_value_t v) {
324 return vtype(v) == T_ERR;
325}
326
327static inline bool is_null(ant_value_t v) {
328 return vtype(v) == T_NULL;
329}
330
331static inline bool is_undefined(ant_value_t v) {
332 return vtype(v) == T_UNDEF;
333}
334
335static inline bool is_empty_slot(ant_value_t v) {
336 return v == T_EMPTY;
337}
338
339static inline bool is_callable(ant_value_t v) {
340 uint8_t t = vtype(v);
341 return t == T_FUNC || t == T_CFUNC;
342}
343
344static inline const ant_cfunc_meta_t *js_as_cfunc_meta(ant_value_t fn_val) {
345 return (const ant_cfunc_meta_t *)(uintptr_t)vdata(fn_val);
346}
347
348static inline ant_cfunc_t js_as_cfunc(ant_value_t fn_val) {
349 const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val);
350 return meta ? meta->fn : NULL;
351}
352
353static inline uint32_t js_cfunc_length(ant_value_t fn_val) {
354 const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val);
355 return meta ? meta->length : 0;
356}
357
358static inline bool js_cfunc_same_entrypoint(ant_value_t fn_val, ant_cfunc_t fn) {
359 const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val);
360 return meta && meta->fn == fn;
361}
362
363size_t uint_to_str(char *buf, size_t bufsize, uint64_t val);
364int extract_array_args(ant_t *js, ant_value_t arr, ant_value_t **out_args);
365
366ant_value_t tov(double d);
367double tod(ant_value_t v);
368double js_to_number(ant_t *js, ant_value_t arg);
369
370bool js_obj_ensure_prop_capacity(ant_object_t *obj, uint32_t needed);
371bool js_obj_ensure_unique_shape(ant_object_t *obj);
372
373ant_value_t js_propref_load(ant_t *js, ant_offset_t handle);
374ant_value_t mkprop(ant_t *js, ant_value_t obj, ant_value_t k, ant_value_t v, uint8_t attrs);
375ant_value_t mkprop_interned(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs);
376ant_value_t mkprop_interned_exact(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs);
377ant_value_t setprop_cstr(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v);
378ant_value_t setprop_interned(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v);
379ant_value_t js_define_property(ant_t *js, ant_value_t obj, ant_value_t prop, ant_value_t descriptor, bool reflect_mode);
380
381// TODO: move into builder.c
382typedef struct {
383 ant_t *js;
384 char *buf;
385 size_t len;
386 size_t n;
387 bool growable;
388 bool inline_mode;
389 bool first;
390 bool closed;
391 bool did_indent;
392} js_inspect_builder_t;
393
394void js_inspect_builder_init_fixed(js_inspect_builder_t *builder, ant_t *js, char *buf, size_t len, size_t initial_n);
395bool js_inspect_builder_init_dynamic(js_inspect_builder_t *builder, ant_t *js, size_t initial_cap);
396void js_inspect_builder_dispose(js_inspect_builder_t *builder);
397bool js_inspect_tagged_header(js_inspect_builder_t *builder, const char *tag, size_t tag_len);
398bool js_inspect_object_body(js_inspect_builder_t *builder, ant_value_t obj);
399bool js_inspect_close(js_inspect_builder_t *builder);
400
401__attribute__((format(printf, 2, 3)))
402bool js_inspect_header(js_inspect_builder_t *builder, const char *fmt, ...);
403
404__attribute__((format(printf, 3, 4)))
405bool js_inspect_header_for(js_inspect_builder_t *builder, ant_value_t obj, const char *fmt, ...);
406
407ant_value_t js_inspect_builder_result(js_inspect_builder_t *builder);
408ant_value_t js_define_own_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t v);
409ant_value_t js_instance_proto_from_new_target(ant_t *js, ant_value_t fallback_proto);
410
411ant_value_t js_get_module_import_binding(ant_t *js);
412ant_value_t js_builtin_import(ant_t *js, ant_value_t *args, int nargs);
413ant_value_t js_create_import_meta(ant_t *js, const char *filename, bool is_main);
414ant_value_t js_create_module_context(ant_t *js, const char *filename, bool is_main);
415ant_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);
416
417void js_arguments_detach(ant_t *js, ant_value_t obj);
418void js_arguments_sync_slot(ant_t *js, ant_value_t obj, uint32_t idx, ant_value_t value);
419
420ant_value_t coerce_to_str(ant_t *js, ant_value_t v);
421ant_value_t coerce_to_str_concat(ant_t *js, ant_value_t v);
422ant_value_t get_ctor_species_value(ant_t *js, ant_value_t ctor);
423
424bool proto_chain_contains(ant_t *js, ant_value_t obj, ant_value_t proto_target);
425bool same_ctor_identity(ant_t *js, ant_value_t a, ant_value_t b);
426
427js_intern_stats_t js_intern_stats(void);
428const char *intern_string(const char *str, size_t len);
429js_cstr_t js_to_cstr(ant_t *js, ant_value_t value, char *stack_buf, size_t stack_size);
430
431ant_value_t lkp_interned_val(ant_t *js, ant_value_t obj, const char *search_intern);
432ant_offset_t lkp_interned(ant_t *js, ant_value_t obj, const char *search_intern, size_t len);
433
434ant_offset_t lkp(ant_t *js, ant_value_t obj, const char *buf, size_t len);
435ant_offset_t lkp_proto(ant_t *js, ant_value_t obj, const char *buf, size_t len);
436
437ant_offset_t lkp_sym(ant_t *js, ant_value_t obj, ant_offset_t sym_off);
438ant_offset_t lkp_sym_proto(ant_t *js, ant_value_t obj, ant_offset_t sym_off);
439
440ant_offset_t vstr(ant_t *js, ant_value_t value, ant_offset_t *len);
441ant_offset_t vstrlen(ant_t *js, ant_value_t value);
442ant_offset_t str_len_fast(ant_t *js, ant_value_t str);
443
444ant_value_t mkval(uint8_t type, uint64_t data);
445ant_value_t mkobj(ant_t *js, ant_offset_t parent);
446ant_value_t js_mkobj_with_inobj_limit(ant_t *js, uint8_t inobj_limit);
447ant_value_t rope_flatten(ant_t *js, ant_value_t rope);
448ant_value_t str_materialize(ant_t *js, ant_value_t value);
449
450ant_value_t js_for_in_keys(ant_t *js, ant_value_t obj);
451ant_value_t js_delete_prop(ant_t *js, ant_value_t obj, const char *key, size_t len);
452ant_value_t js_delete_sym_prop(ant_t *js, ant_value_t obj, ant_value_t sym);
453
454bool is_proxy(ant_value_t obj);
455bool strict_eq_values(ant_t *js, ant_value_t l, ant_value_t r);
456bool js_deep_equal(ant_t *js, ant_value_t a, ant_value_t b, bool strict);
457
458ant_value_t js_proxy_apply(ant_t *js, ant_value_t proxy, ant_value_t this_arg, ant_value_t *args, int argc);
459ant_value_t js_proxy_construct(ant_t *js, ant_value_t proxy, ant_value_t *args, int argc, ant_value_t new_target);
460ant_value_t sv_call_native(ant_t *js, ant_value_t func, ant_value_t this_val, ant_value_t *args, int nargs);
461
462const char *typestr(uint8_t t);
463ant_value_t unwrap_primitive(ant_t *js, ant_value_t val);
464ant_value_t do_string_op(ant_t *js, uint8_t op, ant_value_t l, ant_value_t r);
465ant_value_t js_to_primitive(ant_t *js, ant_value_t value, int hint);
466
467ant_value_t do_instanceof(ant_t *js, ant_value_t l, ant_value_t r);
468ant_value_t do_in(ant_t *js, ant_value_t l, ant_value_t r);
469
470bool js_is_prototype_of(ant_t *js, ant_value_t proto_obj, ant_value_t obj);
471ant_value_t builtin_object_isPrototypeOf(ant_t *js, ant_value_t *args, int nargs);
472ant_value_t builtin_object_freeze(ant_t *js, ant_value_t *args, int nargs);
473
474bool js_is_array_includes_builtin(ant_value_t func);
475ant_value_t js_array_includes_call(ant_t *js, ant_value_t this_val, ant_value_t *args, int nargs);
476ant_value_t builtin_array_includes(ant_t *js, ant_value_t *args, int nargs);
477
478void js_module_eval_ctx_push(ant_t *js, ant_module_t *ctx);
479void js_module_eval_ctx_pop(ant_t *js, ant_module_t *ctx);
480
481bool lookup_prop_meta(
482 ant_t *js, ant_value_t cur_obj,
483 prop_meta_key_t key_kind,
484 const char *key, size_t klen,
485 ant_offset_t sym_off, prop_meta_t *out
486);
487
488static inline ant_value_t js_module_eval_active_ns(ant_t *js) {
489 ant_module_t *ctx = js->module;
490 return ctx ? ctx->module_ns : js_mkundef();
491}
492
493static inline ant_value_t js_module_eval_active_ctx(ant_t *js) {
494 ant_module_t *ctx = js->module;
495 return ctx ? ctx->module_ctx : js_mkundef();
496}
497
498static inline ant_value_t js_module_eval_active_import_meta(ant_t *js) {
499 ant_value_t module_ctx = js_module_eval_active_ctx(js);
500 return is_object_type(module_ctx) ? js_get(js, module_ctx, "meta") : js_mkundef();
501}
502
503static inline const char *js_module_eval_active_filename(ant_t *js) {
504 ant_value_t module_ctx = js_module_eval_active_ctx(js);
505 if (is_object_type(module_ctx)) {
506 ant_value_t filename = js_get(js, module_ctx, "filename");
507 if (vtype(filename) == T_STR) return js_getstr(js, filename, NULL);
508 }
509 return js->filename;
510}
511
512static inline ant_module_format_t js_module_eval_active_format(ant_t *js) {
513 ant_module_t *ctx = js->module;
514 return ctx ? ctx->format : MODULE_EVAL_FORMAT_UNKNOWN;
515}
516
517static inline bool is_length_key(const char *key, size_t len) {
518 return len == 6 && !memcmp(key, "length", 6);
519}
520
521// TODO: move strings helpers to strings.h
522static inline bool str_is_heap_rope(ant_value_t value) {
523 return vtype(value) == T_STR && ((vdata(value) & STR_HEAP_TAG_MASK) == STR_HEAP_TAG_ROPE);
524}
525
526static inline bool str_is_heap_builder(ant_value_t value) {
527 return vtype(value) == T_STR && ((vdata(value) & STR_HEAP_TAG_MASK) == STR_HEAP_TAG_BUILDER);
528}
529
530static inline ant_rope_heap_t *ant_str_rope_ptr(ant_value_t value) {
531 return (ant_rope_heap_t *)(uintptr_t)(vdata(value) & ~STR_HEAP_TAG_MASK);
532}
533
534static inline ant_string_builder_t *ant_str_builder_ptr(ant_value_t value) {
535 return (ant_string_builder_t *)(uintptr_t)(vdata(value) & ~STR_HEAP_TAG_MASK);
536}
537
538static inline ant_value_t ant_mkrope_value(ant_rope_heap_t *rope) {
539 return mkval(T_STR, ((uintptr_t)rope) | STR_HEAP_TAG_ROPE);
540}
541
542static inline ant_value_t ant_mkbuilder_value(ant_string_builder_t *builder) {
543 return mkval(T_STR, ((uintptr_t)builder) | STR_HEAP_TAG_BUILDER);
544}
545
546static inline int js_brand_id(ant_value_t obj) {
547 if (!is_object_type(obj)) return BRAND_NONE;
548 ant_value_t brand = js_get_slot(obj, SLOT_BRAND);
549 return vtype(brand) == T_NUM ? (int)js_getnum(brand) : BRAND_NONE;
550}
551
552static inline bool js_check_brand(ant_value_t obj, int brand) {
553 return js_brand_id(obj) == brand;
554}
555
556static inline bool lookup_symbol_prop_meta(ant_value_t cur_obj, ant_offset_t sym_off, prop_meta_t *out) {
557 return lookup_prop_meta(NULL, cur_obj, PROP_META_SYMBOL, NULL, 0, sym_off, out);
558}
559
560static inline bool lookup_string_prop_meta(ant_t *js, ant_value_t cur_obj, const char *key, size_t klen, prop_meta_t *out) {
561 return lookup_prop_meta(js, cur_obj, PROP_META_STRING, key, klen, 0, out);
562}
563
564static inline ant_value_t defmethod(ant_t *js, ant_value_t obj, const char *name, size_t len, ant_value_t fn) {
565 const char *interned = intern_string(name, len);
566 if (!interned) return js_mkerr(js, "oom");
567
568 return mkprop_interned(
569 js, obj, interned, fn,
570 ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE
571 );
572}
573
574static inline ant_value_t defalias(ant_t *js, ant_value_t obj, const char *name, size_t len, ant_value_t fn) {
575 const char *interned = intern_string(name, len);
576 if (!interned) return js_mkerr(js, "oom");
577
578 return mkprop_interned_exact(
579 js, obj, interned, fn,
580 ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE
581 );
582}
583
584static inline ant_flat_string_t *str_flat_from_bytes(const char *str) {
585 return (ant_flat_string_t *)((char *)str - offsetof(ant_flat_string_t, bytes));
586}
587
588static inline ant_flat_string_t *ant_str_flat_ptr(ant_value_t value) {
589 if (vtype(value) != T_STR) return NULL;
590 if ((vdata(value) & STR_HEAP_TAG_MASK) != STR_HEAP_TAG_FLAT) return NULL;
591 return (ant_flat_string_t *)(uintptr_t)vdata(value);
592}
593
594static inline ant_flat_string_t *large_string_flat_ptr(ant_large_string_alloc_t *alloc) {
595 return alloc ? (ant_flat_string_t *)&alloc->len : NULL;
596}
597
598static inline ant_large_string_alloc_t *large_string_alloc_from_flat(ant_flat_string_t *flat) {
599 return flat ? (ant_large_string_alloc_t *)((char *)flat - offsetof(ant_large_string_alloc_t, len)) : NULL;
600}
601
602static inline uint8_t str_detect_ascii_bytes(const char *str, size_t len) {
603 const unsigned char *s = (const unsigned char *)str;
604 for (size_t i = 0; i < len; i++) {
605 if (s[i] >= 0x80) return STR_ASCII_NO;
606 }
607 return STR_ASCII_YES;
608}
609
610static inline void str_set_ascii_state(const char *str, uint8_t state) {
611 ant_flat_string_t *flat = str_flat_from_bytes(str);
612 flat->is_ascii = state;
613}
614
615static inline bool str_is_ascii(const char *str) {
616 ant_flat_string_t *flat = str_flat_from_bytes(str);
617 if (flat->is_ascii == STR_ASCII_UNKNOWN) {
618 flat->is_ascii = str_detect_ascii_bytes(flat->bytes, (size_t)flat->len);
619 }
620 return flat->is_ascii == STR_ASCII_YES;
621}
622
623static inline void js_set_module_default(ant_t *js, ant_value_t lib, ant_value_t ctor_fn, const char *name) {
624 js_set(js, ctor_fn, name, ctor_fn);
625 js_set(js, lib, name, ctor_fn);
626 js_set(js, lib, "default", ctor_fn);
627 js_set(js, ctor_fn, "default", ctor_fn);
628 js_set_slot_wb(js, lib, SLOT_DEFAULT, ctor_fn);
629}
630
631ant_value_t js_cfunc_promote(ant_t *js, ant_value_t cfunc);
632ant_value_t js_cfunc_expose_named(ant_t *js, ant_value_t cfunc, const char *name, size_t name_len);
633
634static inline ant_value_t js_cfunc_lookup_promoted(ant_t *js, ant_value_t cfunc) {
635 uintptr_t ptr = vdata(cfunc);
636 for (uint8_t i = 0; i < js->cfunc_promote_cache.len; i++) if (
637 js->cfunc_promote_cache.cfunc_ptr[i] == ptr
638 ) return js->cfunc_promote_cache.promoted[i];
639 return cfunc;
640}
641
642static inline ant_value_t js_make_ctor(ant_t *js, ant_cfunc_t fn, ant_value_t proto, const char *name, size_t nlen) {
643 ant_value_t obj = js_mkobj(js);
644 js_set_slot(obj, SLOT_CFUNC, js_mkfun_dyn(fn));
645 js_mkprop_fast(js, obj, "prototype", 9, proto);
646 js_mkprop_fast(js, obj, "name", 4, js_mkstr(js, name, nlen));
647 js_set_descriptor(js, obj, "name", 4, 0);
648
649 ant_value_t fn_val = js_obj_to_func(obj);
650 js_set(js, proto, "constructor", fn_val);
651 js_set_descriptor(js, proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
652
653 return fn_val;
654}
655
656#endif