Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417#include "gc.h"#include "utils.h"#include "shapes.h"#include "internal.h"#include "descriptors.h"#include "silver/engine.h"
#include <assert.h>#include <string.h>
descriptor_entry_t *desc_registry = NULL;
static descriptor_entry_t arr_length_desc = { .key = 0, .obj_off = 0, .prop_name = "length", .prop_len = 6, .writable = true, .enumerable = false, .configurable = false, .has_getter = false, .has_setter = false, .getter = 0, .setter = 0,};
static inline bool is_canonical_desc_obj(ant_value_t obj) { return vtype(obj) == T_OBJ;}
static inline bool is_exotic_desc_obj(ant_value_t obj) { ant_object_t *ptr = js_obj_ptr(obj); return ptr && ptr->is_exotic;}
static inline bool desc_registry_allowed(ant_value_t obj) { if (is_exotic_desc_obj(obj)) return true;#ifndef NDEBUG assert(false && "desc_registry is exotic-only; ordinary objects must use shape metadata");#endif return false;}
static bool ensure_added_shape_slot_storage(ant_object_t *ptr, uint32_t slot) { if (!ptr || !ptr->shape) return false; if (!js_obj_ensure_prop_capacity(ptr, ant_shape_count(ptr->shape))) return false; if (slot >= ptr->prop_count && !js_obj_ensure_prop_capacity(ptr, slot + 1)) return false; return true;}
static inline uint8_t attrs_from_flags(int flags, bool include_writable) { uint8_t attrs = 0; if (include_writable && (flags & JS_DESC_W)) attrs |= ANT_PROP_ATTR_WRITABLE; if (flags & JS_DESC_E) attrs |= ANT_PROP_ATTR_ENUMERABLE; if (flags & JS_DESC_C) attrs |= ANT_PROP_ATTR_CONFIGURABLE; return attrs;}
uint64_t make_desc_key(ant_value_t obj, const char *key, size_t klen) { assert(is_canonical_desc_obj(obj) && "descriptor APIs require canonical js_as_obj(...) value"); if (!is_canonical_desc_obj(obj)) return hash_key(key, klen); uintptr_t obj_off = (uintptr_t)vdata(obj); uint64_t key_hash = hash_key(key, klen); uint64_t h = (uint64_t)obj_off ^ ((uint64_t)obj_off >> 33); h ^= key_hash + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); return h;}
uint64_t make_sym_desc_key(ant_value_t obj, ant_offset_t sym_off) { assert(is_canonical_desc_obj(obj) && "descriptor APIs require canonical js_as_obj(...) value"); if (!is_canonical_desc_obj(obj)) return ((uint64_t)sym_off << 1) | 1u; uintptr_t obj_off = (uintptr_t)vdata(obj); uint64_t h = (uint64_t)obj_off ^ ((uint64_t)obj_off >> 33); h ^= ((uint64_t)sym_off << 1) | 1u; h += 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); return h;}
static descriptor_entry_t *registry_lookup_desc(ant_value_t obj, const char *key, size_t klen) { descriptor_entry_t *entry = NULL; uint64_t desc_key = make_desc_key(obj, key, klen); HASH_FIND(hh, desc_registry, &desc_key, sizeof(uint64_t), entry); return entry;}
static descriptor_entry_t *registry_lookup_sym_desc(ant_value_t obj, ant_offset_t sym_off) { descriptor_entry_t *entry = NULL; uint64_t k = make_sym_desc_key(obj, sym_off); HASH_FIND(hh, desc_registry, &k, sizeof(uint64_t), entry); return entry;}
descriptor_entry_t *lookup_descriptor(ant_value_t obj, const char *key, size_t klen) { assert(is_canonical_desc_obj(obj) && "lookup_descriptor expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return NULL;
ant_object_t *ptr = js_obj_ptr(obj); if (klen == 6 && memcmp(key, "length", 6) == 0 && ptr && ptr->type_tag == T_ARR) return &arr_length_desc;
if (!is_exotic_desc_obj(obj)) return NULL; return registry_lookup_desc(obj, key, klen);}
descriptor_entry_t *lookup_sym_descriptor(ant_value_t obj, ant_offset_t sym_off) { assert(is_canonical_desc_obj(obj) && "lookup_sym_descriptor expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return NULL;
if (!is_exotic_desc_obj(obj)) return NULL; return registry_lookup_sym_desc(obj, sym_off);}
static descriptor_entry_t *get_or_create_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen) { if (!desc_registry_allowed(obj)) return NULL; descriptor_entry_t *entry = registry_lookup_desc(obj, key, klen); if (entry) return entry;
entry = (descriptor_entry_t *)ant_calloc(sizeof(descriptor_entry_t) + klen + 1); if (!entry) return NULL;
entry->key = make_desc_key(obj, key, klen); entry->obj_off = (uintptr_t)vdata(obj); entry->prop_name = (char *)(entry + 1); memcpy(entry->prop_name, key, klen); entry->prop_name[klen] = '\0'; entry->prop_len = klen; entry->writable = true; entry->enumerable = true; entry->configurable = true; entry->has_getter = false; entry->has_setter = false; entry->getter = js_mkundef(); entry->setter = js_mkundef();
HASH_ADD(hh, desc_registry, key, sizeof(uint64_t), entry); return entry;}
static descriptor_entry_t *get_or_create_sym_desc(ant_value_t obj, ant_offset_t sym_off) { if (!desc_registry_allowed(obj)) return NULL; descriptor_entry_t *entry = registry_lookup_sym_desc(obj, sym_off); if (entry) return entry;
entry = (descriptor_entry_t *)ant_calloc(sizeof(descriptor_entry_t)); if (!entry) return NULL;
entry->key = make_sym_desc_key(obj, sym_off); entry->obj_off = (uintptr_t)vdata(obj); entry->sym_off = sym_off; entry->writable = true; entry->enumerable = true; entry->configurable = true; entry->has_getter = false; entry->has_setter = false; entry->getter = js_mkundef(); entry->setter = js_mkundef();
HASH_ADD(hh, desc_registry, key, sizeof(uint64_t), entry); return entry;}
static bool ensure_string_shape_slot(ant_t *js, ant_value_t obj, const char *key, size_t klen, uint32_t *out_slot) { ant_object_t *ptr = js_obj_ptr(obj); if (!ptr || !ptr->shape) return false;
const char *interned = intern_string(key, klen); if (!interned) return false;
int32_t slot = ant_shape_lookup_interned(ptr->shape, interned); if (slot < 0) { uint32_t added_slot = 0; if (!ant_shape_add_interned_tr(&ptr->shape, interned, ANT_PROP_ATTR_DEFAULT, &added_slot)) return false; if (!ensure_added_shape_slot_storage(ptr, added_slot)) return false; slot = (int32_t)added_slot; }
if (out_slot) *out_slot = (uint32_t)slot; return true;}
static bool ensure_symbol_shape_slot(ant_t *js, ant_value_t obj, ant_offset_t sym_off, uint32_t *out_slot) { ant_object_t *ptr = js_obj_ptr(obj); if (!ptr || !ptr->shape) return false;
int32_t slot = ant_shape_lookup_symbol(ptr->shape, sym_off); if (slot < 0) { ant_value_t sym = mkval(T_SYMBOL, sym_off); if (is_err(mkprop(js, obj, sym, js_mkundef(), 0))) return false; slot = ant_shape_lookup_symbol(ptr->shape, sym_off); if (slot < 0) return false; }
if (out_slot) *out_slot = (uint32_t)slot; return true;}
static ant_shape_prop_t *ensure_string_shape_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen) { uint32_t slot = 0; if (!ensure_string_shape_slot(js, obj, key, klen, &slot)) return NULL; ant_object_t *ptr = js_obj_ptr(obj); if (!ptr || !ptr->shape) return NULL; if (!js_obj_ensure_unique_shape(ptr)) return NULL; return ant_shape_prop_mut_at(ptr->shape, slot);}
static ant_shape_prop_t *ensure_symbol_shape_prop(ant_t *js, ant_value_t obj, ant_offset_t sym_off) { uint32_t slot = 0; if (!ensure_symbol_shape_slot(js, obj, sym_off, &slot)) return NULL; ant_object_t *ptr = js_obj_ptr(obj); if (!ptr || !ptr->shape) return NULL; if (!js_obj_ensure_unique_shape(ptr)) return NULL; return ant_shape_prop_mut_at(ptr->shape, slot);}
static void apply_shape_desc_update( ant_shape_prop_t *prop, int flags, bool include_writable, bool set_getter_flag, bool has_getter, ant_value_t getter, bool set_setter_flag, bool has_setter, ant_value_t setter) { if (!prop) return; prop->attrs = attrs_from_flags(flags, include_writable); if (set_getter_flag) { prop->has_getter = has_getter ? 1 : 0; prop->getter = has_getter ? getter : js_mkundef(); } if (set_setter_flag) { prop->has_setter = has_setter ? 1 : 0; prop->setter = has_setter ? setter : js_mkundef(); }}
static void apply_registry_desc_update( descriptor_entry_t *entry, int flags, bool include_writable, bool set_getter_flag, bool has_getter, ant_value_t getter, bool set_setter_flag, bool has_setter, ant_value_t setter) { if (!entry) return; if (include_writable) entry->writable = (flags & JS_DESC_W) != 0; entry->enumerable = (flags & JS_DESC_E) != 0; entry->configurable = (flags & JS_DESC_C) != 0; if (set_getter_flag) { entry->has_getter = has_getter; entry->getter = has_getter ? getter : js_mkundef(); } if (set_setter_flag) { entry->has_setter = has_setter; entry->setter = has_setter ? setter : js_mkundef(); }}
void js_set_descriptor(ant_t *js, ant_value_t obj, const char *key, size_t klen, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_descriptor expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return;
ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); if (prop) { apply_shape_desc_update( prop, flags, true, false, false, js_mkundef(), false, false, js_mkundef() ); ant_ic_epoch_bump(); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); apply_registry_desc_update( entry, flags, true, false, false, js_mkundef(), false, false, js_mkundef() );}
void js_set_getter_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t getter, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_getter_desc expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return;
ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); if (prop) { apply_shape_desc_update( prop, flags, false, true, true, getter, false, false, js_mkundef() ); ant_ic_epoch_bump(); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); apply_registry_desc_update( entry, flags, false, true, true, getter, false, false, js_mkundef() );}
void js_set_setter_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t setter, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_setter_desc expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return;
ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); if (prop) { apply_shape_desc_update( prop, flags, false, false, false, js_mkundef(), true, true, setter ); ant_ic_epoch_bump(); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); apply_registry_desc_update( entry, flags, false, false, false, js_mkundef(), true, true, setter );}
void js_set_accessor_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t getter, ant_value_t setter, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_accessor_desc expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return;
ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); if (prop) { apply_shape_desc_update( prop, flags, false, true, true, getter, true, true, setter ); ant_ic_epoch_bump(); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); apply_registry_desc_update( entry, flags, false, true, true, getter, true, true, setter );}
void js_set_sym_getter_desc(ant_t *js, ant_value_t obj, ant_value_t sym, ant_value_t getter, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_sym_getter_desc expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return; if (vtype(sym) != T_SYMBOL) return; ant_offset_t sym_off = (ant_offset_t)vdata(sym);
ant_shape_prop_t *prop = ensure_symbol_shape_prop(js, obj, sym_off); if (prop) { apply_shape_desc_update( prop, flags, false, true, true, getter, false, false, js_mkundef() ); ant_ic_epoch_bump(); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_sym_desc(obj, sym_off); apply_registry_desc_update( entry, flags, false, true, true, getter, false, false, js_mkundef() );}
void js_set_sym_setter_desc(ant_t *js, ant_value_t obj, ant_value_t sym, ant_value_t setter, int flags) { assert(is_canonical_desc_obj(obj) && "js_set_sym_setter_desc expects js_as_obj(...)"); if (!is_canonical_desc_obj(obj)) return; if (vtype(sym) != T_SYMBOL) return; ant_offset_t sym_off = (ant_offset_t)vdata(sym);
ant_shape_prop_t *prop = ensure_symbol_shape_prop(js, obj, sym_off); if (prop) { apply_shape_desc_update( prop, flags, false, false, false, js_mkundef(), true, true, setter ); ant_ic_epoch_bump(); gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); return; }
if (!desc_registry_allowed(obj)) return; descriptor_entry_t *entry = get_or_create_sym_desc(obj, sym_off); apply_registry_desc_update( entry, flags, false, false, false, js_mkundef(), true, true, setter );}