Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454#ifndef ANT_OBJECT_H#define ANT_OBJECT_H
#include "types.h"#include "value.h"#include "sugar.h"#include "shapes.h"
#include <utarray.h>#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include <stdlib.h>
typedef enum: uint8_t { ANT_EXOTIC_KEYS_ANY, ANT_EXOTIC_KEYS_NUMERIC,} ant_exotic_keys_t;
typedef struct { ant_value_t (*getter)(ant_t *, ant_value_t, const char *, size_t); bool (*setter)(ant_t *, ant_value_t, const char *, size_t, ant_value_t); bool (*deleter)(ant_t *, ant_value_t, const char *, size_t); ant_value_t (*definer)(ant_t *, ant_value_t, const char *, size_t, ant_value_t value, bool has_value, bool plain_data); ant_exotic_keys_t keys;} ant_exotic_ops_t;
typedef struct { const char *name; ant_value_t (*get)(ant_t *, ant_value_t target, const char *key, size_t key_len); ant_value_t (*set)(ant_t *, ant_value_t target, const char *key, size_t key_len, ant_value_t value); ant_value_t (*del)(ant_t *, ant_value_t target, const char *key, size_t key_len); ant_value_t (*keys)(ant_t *, ant_value_t target); ant_value_t (*flat_entries)(ant_t *, ant_value_t target);} ant_host_proxy_ops_t;
typedef struct promise_handler { ant_value_t onFulfilled; ant_value_t onRejected; ant_value_t nextPromise; struct coroutine *await_coro;} promise_handler_t;
typedef struct ant_promise_state { ant_value_t value; ant_value_t trigger_parent; struct ant_object *gc_pending_next; struct ant_object *gc_pending_prev; promise_handler_t inline_handler; UT_array *handlers; uint32_t promise_id; uint8_t state; bool has_inline_handler: 1; bool trigger_queued: 1; bool has_rejection_handler: 1; bool processing: 1; bool unhandled_reported: 1; bool gc_pending_rooted: 1;} ant_promise_state_t;
static_assert( sizeof(void *) != 8 || sizeof(ant_promise_state_t) == 80, "promise state no longer fits an 80-byte allocation");
typedef struct { ant_value_t target; ant_value_t handler; const ant_host_proxy_ops_t *host; bool revoked; uint32_t plain_handler_epoch;} ant_proxy_state_t;
typedef struct { uint8_t slot; ant_value_t value;} ant_extra_slot_t;
typedef struct { ant_value_t token; ant_value_t value; ant_value_t getter; ant_value_t setter; uint32_t hash; uint8_t kind; uint8_t occupied;} ant_private_entry_t;
typedef struct { ant_private_entry_t *entries; uint32_t count; uint32_t cap;} ant_private_table_t;
typedef struct { void *ptr; uint32_t tag;} ant_native_entry_t;
typedef struct { ant_extra_slot_t *extra_slots; ant_native_entry_t *native_entries; ant_private_table_t private_table; ant_proxy_state_t *proxy_state; sv_eval_env_state_t *eval_env_state; gc_card_table_t *gc_cards; ant_exotic_ops_t *owned_exotic_ops; uint8_t native_count; uint8_t native_cap; uint8_t extra_count; uint8_t extra_cap; uint8_t flags;} ant_object_sidecar_t;
static_assert( _Alignof(ant_object_sidecar_t) > ant_sidecar, "object sidecar pointer uses low-bit tag");
typedef union ant_object_flags { struct { uint8_t extensible: 1; uint8_t frozen: 1; uint8_t sealed: 1; uint8_t is_exotic: 1; uint8_t is_constructor: 1; uint8_t is_callable: 1; uint8_t fast_array: 1; uint8_t may_have_holes: 1; uint8_t may_have_dense_elements: 1; uint8_t gc_permanent: 1; uint8_t generation: 1; uint8_t in_remember_set: 1; uint8_t guards_absence: 1; uint8_t dense_length_fits: 1; uint8_t arguments_object: 1; uint8_t regexp_brand: 1; }; uint16_t raw; uint8_t bytes[2];} ant_object_flags_t;
typedef enum: uint16_t { ANT_OBJECT_FLAG_EXTENSIBLE = 1u << 0, ANT_OBJECT_FLAG_FROZEN = 1u << 1, ANT_OBJECT_FLAG_SEALED = 1u << 2, ANT_OBJECT_FLAG_EXOTIC = 1u << 3, ANT_OBJECT_FLAG_FAST_ARRAY = 1u << 6, ANT_OBJECT_FLAG_MAY_HAVE_DENSE_ELEMENTS = 1u << 8, ANT_OBJECT_FLAG_GENERATION = 1u << 10, ANT_OBJECT_FLAG_REMEMBERED = 1u << 11, ANT_OBJECT_FLAG_GUARDS_ABSENCE = 1u << 12, ANT_OBJECT_FLAG_DENSE_LENGTH_FITS = 1u << 13, ANT_OBJECT_FLAG_ARGUMENTS = 1u << 14, ANT_OBJECT_FLAG_REGEXP_BRAND = 1u << 15,} ant_object_flag_mask_t;
static_assert( sizeof(ant_object_flags_t) == 2, "ant_object_flags_t must cover the packed object bitfields");
static inline bool ant_object_flag_masks_match_layout(void) { ant_object_flags_t flags = {.extensible = 1}; if (flags.raw != ANT_OBJECT_FLAG_EXTENSIBLE) return false;
flags = (ant_object_flags_t){.frozen = 1}; if (flags.raw != ANT_OBJECT_FLAG_FROZEN) return false;
flags = (ant_object_flags_t){.sealed = 1}; if (flags.raw != ANT_OBJECT_FLAG_SEALED) return false;
flags = (ant_object_flags_t){.is_exotic = 1}; if (flags.raw != ANT_OBJECT_FLAG_EXOTIC) return false;
flags = (ant_object_flags_t){.fast_array = 1}; if (flags.raw != ANT_OBJECT_FLAG_FAST_ARRAY) return false;
flags = (ant_object_flags_t){.may_have_dense_elements = 1}; if (flags.raw != ANT_OBJECT_FLAG_MAY_HAVE_DENSE_ELEMENTS) return false;
flags = (ant_object_flags_t){.generation = 1}; if (flags.raw != ANT_OBJECT_FLAG_GENERATION) return false;
flags = (ant_object_flags_t){.in_remember_set = 1}; if (flags.raw != ANT_OBJECT_FLAG_REMEMBERED) return false;
flags = (ant_object_flags_t){.guards_absence = 1}; if (flags.raw != ANT_OBJECT_FLAG_GUARDS_ABSENCE) return false;
flags = (ant_object_flags_t){.dense_length_fits = 1}; if (flags.raw != ANT_OBJECT_FLAG_DENSE_LENGTH_FITS) return false;
flags = (ant_object_flags_t){.arguments_object = 1}; if (flags.raw != ANT_OBJECT_FLAG_ARGUMENTS) return false;
flags = (ant_object_flags_t){.regexp_brand = 1}; return flags.raw == ANT_OBJECT_FLAG_REGEXP_BRAND;}
typedef struct ant_object { struct ant_object *next; ant_value_t proto; ant_shape_t *shape; ant_value_t *overflow_prop; const ant_exotic_ops_t *exotic_ops; ant_extra_slot_t *extra_slots; void (*finalizer)(ant_t *, struct ant_object *); ant_value_t inobj[ANT_INOBJ_MAX_SLOTS];
void *native_ptr; uint32_t native_tag; uint8_t protector_holder;
union { struct { ant_value_t *data; uint32_t len; uint32_t cap; } array; struct { sv_closure_t *closure; } func; struct { ant_value_t value; } data; struct { ant_value_t value; ant_value_t stack; } exception; struct { ant_value_t value; ant_promise_state_t *state; } promise; } u;
uint32_t prop_count; uint8_t mark_epoch; uint8_t type_tag; uint8_t inobj_limit; uint8_t extra_count; uint8_t extra_cap; uint8_t overflow_cap; ant_object_flags_t flags; uint32_t ic_identity;} ant_object_t;
static constexpr size_t ANT_OBJECT_FLAGS_HIGH_BYTE = offsetof(ant_object_t, flags) + 1;
static_assert( sizeof(void *) != 8 || ANT_INOBJ_MAX_SLOTS != 4 || sizeof(ant_object_t) == 136, "ordinary 64-bit object layout changed");
static_assert( offsetof(ant_object_t, u.promise.value) == offsetof(ant_object_t, u.data.value), "promise objects keep SLOT_DATA in u.data.value");
static_assert( offsetof(ant_object_t, u.promise.state) == offsetof(ant_object_t, u.array.len) && offsetof(ant_object_t, u.promise.state) + sizeof(ant_promise_state_t *) == offsetof(ant_object_t, u.array.cap) + sizeof(uint32_t), "obj_alloc clears the promise state pointer through u.array.len and u.array.cap");
static_assert( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "ANT_OBJECT_FLAGS_HIGH_BYTE assumes a little-endian flags word");
static_assert( ANT_OBJECT_FLAG_ARGUMENTS >= 0x100, "the arguments flag must live in the high flags byte");
static_assert( (0xffffu & ~((ANT_OBJECT_FLAG_ARGUMENTS << 1) - 1u)) == ANT_OBJECT_FLAG_REGEXP_BRAND, "only the RegExp brand may sit above the arguments flag");
enum { ANT_ARGUMENTS_SLOT_LENGTH = 0, ANT_ARGUMENTS_SLOT_CALLEE = 1, ANT_ARGUMENTS_SLOT_ITERATOR = 2,};
static inline bool ant_object_is_array(const ant_object_t *obj) { return obj && obj->type_tag == kTypeArray && !obj->flags.arguments_object;}
static inline bool ant_object_is_arguments(const ant_object_t *obj) { return obj && obj->type_tag == kTypeArray && obj->flags.arguments_object;}
static inline bool js_is_array(ant_value_t v) { return vtype(v) == kTypeArray && !((const ant_object_t *)vptr(v))->flags.arguments_object;}
static inline bool js_is_arguments(ant_value_t v) { return vtype(v) == kTypeArray && ((const ant_object_t *)vptr(v))->flags.arguments_object;}
static inline void ant_object_guard_absence(ant_object_t *obj) { if (obj) obj->flags.guards_absence = 1;}
static inline bool ant_object_has_sidecar(const ant_object_t *obj) { return obj && (((uintptr_t)obj->extra_slots & ant_sidecar) != 0);}
static inline ant_object_sidecar_t *ant_object_sidecar(const ant_object_t *obj) { if (!ant_object_has_sidecar(obj)) return NULL; return (ant_object_sidecar_t *)((uintptr_t)obj->extra_slots & ~ant_sidecar);}
static inline ant_extra_slot_t *ant_object_extra_slots_ptr(const ant_object_t *obj) { if (!obj) return NULL; uintptr_t raw = (uintptr_t)obj->extra_slots; if ((raw & ant_sidecar) == 0) return obj->extra_slots; return ((ant_object_sidecar_t *)(raw & ~ant_sidecar))->extra_slots;}
static inline uint8_t ant_object_extra_count(const ant_object_t *obj) { if (!obj) return 0; uintptr_t raw = (uintptr_t)obj->extra_slots; if ((raw & ant_sidecar) == 0) return obj->extra_count; return ((ant_object_sidecar_t *)(raw & ~ant_sidecar))->extra_count;}
static inline uint8_t ant_object_extra_capacity(const ant_object_t *obj) { if (!obj) return 0; uintptr_t raw = (uintptr_t)obj->extra_slots; if ((raw & ant_sidecar) == 0) return obj->extra_cap; return ((ant_object_sidecar_t *)(raw & ~ant_sidecar))->extra_cap;}
static inline ant_extra_slot_t *ant_object_extra_slots(const ant_object_t *obj, uint8_t *count) { if (!obj) { if (count) *count = 0; return NULL; }
uintptr_t raw = (uintptr_t)obj->extra_slots; if ((raw & ant_sidecar) == 0) { if (count) *count = obj->extra_count; return obj->extra_slots; } ant_object_sidecar_t *sidecar = (ant_object_sidecar_t *)(raw & ~ant_sidecar); if (count) *count = sidecar->extra_count; return sidecar->extra_slots;}
static inline ant_extra_slot_t *ant_object_extra_slot(const ant_object_t *obj, uint8_t slot) { if (!obj) return NULL;
uint8_t count = obj->extra_count; ant_extra_slot_t *entries = obj->extra_slots;
uintptr_t raw = (uintptr_t)obj->extra_slots; if ((raw & ant_sidecar) != 0) { ant_object_sidecar_t *sidecar = (ant_object_sidecar_t *)(raw & ~ant_sidecar); count = sidecar->extra_count; entries = sidecar->extra_slots; } for (uint8_t i = 0; i < count; i++) if (entries[i].slot == slot) return &entries[i]; return NULL;}
static inline ant_object_sidecar_t *ant_object_ensure_sidecar(ant_object_t *obj) { if (!obj) return NULL; ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); if (sidecar) return sidecar;
sidecar = (ant_object_sidecar_t *)calloc(1, sizeof(*sidecar)); if (!sidecar) return NULL; sidecar->extra_slots = obj->extra_slots; sidecar->extra_count = obj->extra_count; sidecar->extra_cap = obj->extra_cap; obj->extra_slots = (ant_extra_slot_t *)((uintptr_t)sidecar | ant_sidecar); obj->extra_count = 0; obj->extra_cap = 0; return sidecar;}
static inline ant_exotic_ops_t *ant_object_owned_exotic_ops(const ant_object_t *obj) { ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); return sidecar && sidecar->owned_exotic_ops == obj->exotic_ops ? sidecar->owned_exotic_ops : NULL;}
static inline ant_proxy_state_t *ant_object_proxy_state(const ant_object_t *obj) { ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); return sidecar ? sidecar->proxy_state : NULL;}
static inline sv_eval_env_state_t *ant_object_eval_env_state(const ant_object_t *obj) { ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); return sidecar ? sidecar->eval_env_state : NULL;}
static inline ant_private_table_t *ant_object_private_table(const ant_object_t *obj) { ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); return sidecar ? (ant_private_table_t *)&sidecar->private_table : NULL;}
static inline ant_promise_state_t *ant_object_promise_state(const ant_object_t *obj) { return obj && obj->type_tag == kTypePromise ? obj->u.promise.state : NULL;}
static inline void ant_object_make_promise(ant_object_t *obj, ant_promise_state_t *state) { obj->type_tag = kTypePromise; obj->u.promise.state = state;}
static inline uint32_t ant_object_overflow_cap(const ant_object_t *obj) { return obj->overflow_cap ? (1u << obj->overflow_cap) : 0;}
static inline uint32_t ant_object_inobj_limit(const ant_object_t *obj) { if (!obj) return ANT_INOBJ_MAX_SLOTS; uint32_t limit = obj->inobj_limit; return (limit > ANT_INOBJ_MAX_SLOTS) ? ANT_INOBJ_MAX_SLOTS : limit;}
static inline ant_value_t ant_object_prop_get_unchecked(const ant_object_t *obj, uint32_t slot) { uint32_t inobj_limit = ant_object_inobj_limit(obj); return (slot < inobj_limit) ? obj->inobj[slot] : obj->overflow_prop[slot - inobj_limit];}
static inline void ant_object_prop_set_unchecked(ant_object_t *obj, uint32_t slot, ant_value_t value) { uint32_t inobj_limit = ant_object_inobj_limit(obj); if (slot < inobj_limit) obj->inobj[slot] = value; else obj->overflow_prop[slot - inobj_limit] = value;}
#endif