diff --git a/include/object.h b/include/object.h index 2f32cac..9f651a7 100644 --- a/include/object.h +++ b/include/object.h @@ -9,6 +9,7 @@ #include #include #include +#include typedef struct { ant_value_t (*getter)(ant_t *, ant_value_t, const char *, size_t); @@ -43,6 +44,43 @@ typedef struct { bool revoked; } 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 { + ant_extra_slot_t *extra_slots; + ant_private_table_t private_table; + ant_proxy_state_t *proxy_state; + + uint8_t extra_count; + uint8_t flags; +} ant_object_sidecar_t; + +typedef struct ant_prop_ref { + ant_object_t *obj; + uint32_t slot; + bool valid; +} ant_prop_ref_t; + typedef struct ant_object { struct ant_object *next; @@ -54,8 +92,7 @@ typedef struct ant_object { ant_value_t (*exotic_keys)(ant_t *, ant_value_t); ant_promise_state_t *promise_state; - ant_proxy_state_t *proxy_state; - ant_value_t *extra_slots; + ant_extra_slot_t *extra_slots; struct ant_object *gc_pending_next; void (*finalizer)(ant_t *, struct ant_object *); @@ -96,16 +133,80 @@ typedef struct ant_object { uint8_t overflow_cap; } ant_object_t; -typedef struct { - uint8_t slot; - ant_value_t value; -} ant_extra_slot_t; +static inline bool ant_object_has_sidecar(const ant_object_t *obj) { + return obj && (((uintptr_t)obj->extra_slots & ant_sidecar) != 0); +} -typedef struct ant_prop_ref { - ant_object_t *obj; - uint32_t slot; - bool valid; -} ant_prop_ref_t; +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; + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); + return sidecar ? sidecar->extra_slots : obj->extra_slots; +} + +static inline uint8_t ant_object_extra_count(const ant_object_t *obj) { + if (!obj) return 0; + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); + return sidecar ? sidecar->extra_count : obj->extra_count; +} + +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; + } + + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); + if (sidecar) { + if (count) *count = sidecar->extra_count; + return sidecar->extra_slots; + } + + if (count) *count = obj->extra_count; + return obj->extra_slots; +} + +static inline ant_extra_slot_t *ant_object_extra_slot(const ant_object_t *obj, uint8_t slot) { + uint8_t count = 0; + ant_extra_slot_t *entries = ant_object_extra_slots(obj, &count); + + 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; + + obj->extra_slots = (ant_extra_slot_t *)((uintptr_t)sidecar | ant_sidecar); + obj->extra_count = 0; + + return sidecar; +} + +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 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 uint32_t ant_object_inobj_limit(const ant_object_t *obj) { if (!obj) return ANT_INOBJ_MAX_SLOTS; diff --git a/include/shapes.h b/include/shapes.h index 7b6703f..4ed597e 100644 --- a/include/shapes.h +++ b/include/shapes.h @@ -36,6 +36,7 @@ typedef struct { ant_shape_t *ant_shape_new(void); ant_shape_t *ant_shape_new_with_inobj_limit(uint8_t inobj_limit); ant_shape_t *ant_shape_clone(const ant_shape_t *shape); + bool ant_shape_is_shared(const ant_shape_t *shape); void ant_shape_retain(ant_shape_t *shape); void ant_shape_release(ant_shape_t *shape); @@ -52,12 +53,13 @@ bool ant_shape_add_symbol_tr(ant_shape_t **shape_pp, ant_offset_t sym_off, uint8 bool ant_shape_remove_slot(ant_shape_t *shape, uint32_t slot, uint32_t *swapped_from); uint32_t ant_shape_count(const ant_shape_t *shape); +uint8_t ant_shape_get_attrs(const ant_shape_t *shape, uint32_t slot); + const ant_shape_prop_t *ant_shape_prop_at(const ant_shape_t *shape, uint32_t slot); ant_shape_prop_t *ant_shape_prop_mut_at(ant_shape_t *shape, uint32_t slot); bool ant_shape_set_attrs_interned(ant_shape_t *shape, const char *interned, uint8_t attrs); bool ant_shape_set_attrs_symbol(ant_shape_t *shape, ant_offset_t sym_off, uint8_t attrs); -uint8_t ant_shape_get_attrs(const ant_shape_t *shape, uint32_t slot); bool ant_shape_clear_accessor_slot(ant_shape_t *shape, uint32_t slot); void ant_gc_shapes_begin(void); diff --git a/include/silver/compiler.h b/include/silver/compiler.h index ea352d5..c25db2b 100644 --- a/include/silver/compiler.h +++ b/include/silver/compiler.h @@ -72,6 +72,7 @@ typedef struct { const char *name; uint32_t len; uint8_t kind; + uint32_t hash; bool is_static; bool has_getter; bool has_setter; diff --git a/include/silver/opcode.h b/include/silver/opcode.h index ab0a728..ed87b63 100644 --- a/include/silver/opcode.h +++ b/include/silver/opcode.h @@ -37,6 +37,7 @@ OP_DEF( FALSE, 1, 0, 1, none) OP_DEF( THIS, 1, 0, 1, none) /* push current 'this' */ OP_DEF( GLOBAL, 1, 0, 1, none) /* push 'globalThis' (js->global) */ OP_DEF( OBJECT, 1, 0, 1, none) /* push empty object {} */ +OP_DEF( PRIVATE_TOKEN, 5, 0, 1, u32) /* push private-name token with cached hash */ OP_DEF( ARRAY, 3, 0, 1, npop) /* push array from stack items */ OP_DEF( SET_BRAND, 2, 1, 1, u8) /* obj -> obj (brand id) */ OP_DEF( REGEXP, 1, 2, 1, none) /* pattern flags -> regexp */ diff --git a/include/types.h b/include/types.h index d7c6cbb..c9fc45e 100644 --- a/include/types.h +++ b/include/types.h @@ -37,6 +37,7 @@ typedef struct ant_cfunc_meta { uint8_t flags; } ant_cfunc_meta_t; +#define ant_sidecar ((uintptr_t)1u) #define ant_bind_t ant_value_t func, ant_value_t this_val #define ant_params_t ant_t *js, ant_value_t *args, int nargs diff --git a/src/ant.c b/src/ant.c index 98f1cef..448cad7 100644 --- a/src/ant.c +++ b/src/ant.c @@ -240,38 +240,41 @@ void js_mark_constructor(ant_value_t value, bool is_constructor) { if (obj) obj->is_constructor = is_constructor ? 1u : 0u; } -static inline ant_extra_slot_t *obj_extra_slots(ant_object_t *obj) { - return (ant_extra_slot_t *)obj->extra_slots; -} - static ant_value_t obj_extra_get(ant_object_t *obj, internal_slot_t slot) { - if (!obj || obj->extra_count == 0) return js_mkundef(); - ant_extra_slot_t *entries = obj_extra_slots(obj); - for (uint8_t i = 0; i < obj->extra_count; i++) { - if ((internal_slot_t)entries[i].slot == slot) return entries[i].value; - } - return js_mkundef(); + ant_extra_slot_t *entry = ant_object_extra_slot(obj, (uint8_t)slot); + return entry ? entry->value : js_mkundef(); } static bool obj_extra_set(ant_object_t *obj, internal_slot_t slot, ant_value_t value) { if (!obj) return false; - ant_extra_slot_t *entries = obj_extra_slots(obj); - for (uint8_t i = 0; i < obj->extra_count; i++) { - if ((internal_slot_t)entries[i].slot == slot) { - entries[i].value = value; - return true; - } + + ant_extra_slot_t *entry = ant_object_extra_slot(obj, (uint8_t)slot); + if (entry) { + entry->value = value; + return true; } - - if (obj->extra_count == UINT8_MAX) return false; - uint8_t next_count = (uint8_t)(obj->extra_count + 1); + + uint8_t count = 0; + ant_extra_slot_t *entries = ant_object_extra_slots(obj, &count); + + if (count == UINT8_MAX) return false; + uint8_t next_count = (uint8_t)(count + 1); + ant_extra_slot_t *next = realloc(entries, sizeof(*next) * next_count); if (!next) return false; - next[obj->extra_count].slot = (uint8_t)slot; - next[obj->extra_count].value = value; - obj->extra_slots = (ant_value_t *)next; - obj->extra_count = next_count; + next[count].slot = (uint8_t)slot; + next[count].value = value; + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); + + if (sidecar) { + sidecar->extra_slots = next; + sidecar->extra_count = next_count; + } else { + obj->extra_slots = next; + obj->extra_count = next_count; + } + return true; } @@ -403,27 +406,47 @@ static ant_object_t *obj_alloc(ant_t *js, uint8_t type_tag, uint8_t inobj_limit) obj->type_tag = type_tag; obj->proto = js_mkundef(); + obj->u.data.value = js_mkundef(); + obj->shape = ant_shape_new_with_inobj_limit(inobj_limit); + if (!obj->shape) { + obj->mark_epoch = ANT_GC_DEAD; + fixed_arena_free_elem(&js->obj_arena, obj); + return NULL; + } + obj->inobj_limit = ant_shape_get_inobj_limit(obj->shape); + obj->overflow_prop = NULL; obj->overflow_cap = 0; obj->prop_count = 0; - obj->inobj_limit = ant_shape_get_inobj_limit(obj->shape); - for (uint32_t i = 0; i < ANT_INOBJ_MAX_SLOTS; i++) obj->inobj[i] = js_mkundef(); - obj->extensible = 1; - obj->frozen = 0; - obj->sealed = 0; - obj->is_exotic = 0; - obj->is_constructor = 0; - obj->fast_array = 0; + obj->propref_count = 0; + + for (uint32_t i = 0; i < ANT_INOBJ_MAX_SLOTS; i++) + obj->inobj[i] = js_mkundef(); + obj->exotic_ops = NULL; obj->exotic_keys = NULL; obj->promise_state = NULL; - obj->proxy_state = NULL; - obj->u.data.value = js_mkundef(); obj->extra_slots = NULL; obj->extra_count = 0; + + obj->finalizer = NULL; obj->gc_pending_next = NULL; obj->gc_pending_rooted = false; + + obj->native.ptr = NULL; + obj->native.tag = 0; + + obj->mark_epoch = 0; + obj->extensible = 1; + obj->frozen = 0; + obj->sealed = 0; + obj->is_exotic = 0; + obj->is_constructor = 0; + obj->fast_array = 0; + obj->may_have_holes = 0; + obj->may_have_dense_elements = 0; + obj->gc_permanent = 0; obj->generation = 0; obj->in_remember_set = 0; @@ -13794,7 +13817,7 @@ void js_module_eval_ctx_pop(ant_t *js, ant_module_t *ctx) { static ant_proxy_state_t *get_proxy_data(ant_value_t obj) { if (vtype(obj) != T_OBJ) return NULL; ant_object_t *ptr = js_obj_ptr(obj); - return ptr ? ptr->proxy_state : NULL; + return ptr ? ant_object_proxy_state(ptr) : NULL; } bool is_proxy(ant_value_t obj) { @@ -14332,7 +14355,14 @@ static ant_value_t mkproxy(ant_t *js, ant_value_t target, ant_value_t handler) { proxy_ptr->is_exotic = 1; js_mark_constructor(proxy_obj, js_is_constructor(target)); - proxy_ptr->proxy_state = data; + + ant_object_sidecar_t *sidecar = ant_object_ensure_sidecar(proxy_ptr); + if (!sidecar) { + free(data); + return js_mkerr(js, "out of memory"); + } + + sidecar->proxy_state = data; return proxy_obj; } diff --git a/src/gc/objects.c b/src/gc/objects.c index 5a209d2..c7e96a1 100644 --- a/src/gc/objects.c +++ b/src/gc/objects.c @@ -266,15 +266,17 @@ static void gc_scan_obj(ant_t *js, ant_object_t *obj) { uint32_t count = ant_shape_count(obj->shape); for (uint32_t i = 0; i < count && i < obj->prop_count; i++) gc_mark_value(js, ant_object_prop_get_unchecked(obj, i)); + for (uint32_t i = 0; i < count; i++) { const ant_shape_prop_t *prop = ant_shape_prop_at(obj->shape, i); if (prop && prop->has_getter) gc_mark_value(js, prop->getter); if (prop && prop->has_setter) gc_mark_value(js, prop->setter); }} - if (obj->extra_slots) { - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) gc_mark_value(js, entries[i].value); + uint8_t extra_count = 0; + ant_extra_slot_t *extra_slots = ant_object_extra_slots(obj, &extra_count); + if (extra_slots) { + for (uint8_t i = 0; i < extra_count; i++) gc_mark_value(js, extra_slots[i].value); } if (obj->type_tag == T_ARR && obj->u.array.data) { @@ -289,9 +291,20 @@ static void gc_scan_obj(ant_t *js, ant_object_t *obj) { gc_mark_promise_handlers(js, pd); } - if (obj->proxy_state) { - gc_mark_value(js, obj->proxy_state->target); - gc_mark_value(js, obj->proxy_state->handler); + ant_proxy_state_t *proxy_state = ant_object_proxy_state(obj); + if (proxy_state) { + gc_mark_value(js, proxy_state->target); + gc_mark_value(js, proxy_state->handler); + } + + ant_private_table_t *table = ant_object_private_table(obj); + if (table && table->entries) for (uint32_t i = 0; i < table->cap; i++) { + ant_private_entry_t *entry = &table->entries[i]; + if (!entry->occupied) continue; + gc_mark_value(js, entry->token); + gc_mark_value(js, entry->value); + gc_mark_value(js, entry->getter); + gc_mark_value(js, entry->setter); } gc_mark_abort_signal_object( @@ -540,7 +553,16 @@ void gc_object_free(ant_t *js, ant_object_t *obj) { obj->shape = NULL; } - if (obj->extra_slots) { + if (ant_object_has_sidecar(obj)) { + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); + free(sidecar->extra_slots); + free(sidecar->proxy_state); + free(sidecar->private_table.entries); + free(sidecar); + obj->extra_slots = NULL; + } + + else if (obj->extra_slots) { free(obj->extra_slots); obj->extra_slots = NULL; } @@ -555,11 +577,6 @@ void gc_object_free(ant_t *js, ant_object_t *obj) { obj->promise_state = NULL; } - if (obj->proxy_state) { - free(obj->proxy_state); - obj->proxy_state = NULL; - } - if (obj->type_tag == T_ARR && obj->u.array.data) { free(obj->u.array.data); obj->u.array.data = NULL; diff --git a/src/modules/blob.c b/src/modules/blob.c index 4e1d457..7bcd5fb 100644 --- a/src/modules/blob.c +++ b/src/modules/blob.c @@ -150,14 +150,10 @@ static ant_value_t process_blob_parts(ant_t *js, byte_buf_t *buf, ant_value_t pa } static void blob_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - blob_data_t *bd = (blob_data_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (bd) { free(bd->data); free(bd->type); free(bd->name); free(bd); } - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + blob_data_t *bd = (blob_data_t *)(uintptr_t)(size_t)js_getnum(slot->value); + if (bd) { free(bd->data); free(bd->type); free(bd->name); free(bd); } } ant_value_t blob_create(ant_t *js, const uint8_t *data, size_t size, const char *type) { diff --git a/src/modules/builtin.c b/src/modules/builtin.c index 542098d..7e0f1e8 100644 --- a/src/modules/builtin.c +++ b/src/modules/builtin.c @@ -249,13 +249,15 @@ static ant_value_t js_stats_fn(ant_t *js, ant_value_t *args, int nargs) { for (ant_object_t *obj = head; obj; obj = obj->next) { obj_count++; obj_bytes += sizeof(ant_object_t); - uint32_t inobj_limit = ant_object_inobj_limit(obj); if (obj->overflow_prop && obj->prop_count > inobj_limit) overflow_bytes += (obj->prop_count - inobj_limit) * sizeof(ant_value_t); - if (obj->extra_slots) extra_bytes += obj->extra_count * sizeof(ant_extra_slot_t); + uint8_t extra_count = 0; + ant_extra_slot_t *slots = ant_object_extra_slots(obj, &extra_count); + if (slots) extra_bytes += extra_count * sizeof(ant_extra_slot_t); if (obj->promise_state) promise_bytes += sizeof(ant_promise_state_t); - if (obj->proxy_state) proxy_bytes += sizeof(ant_proxy_state_t); + if (ant_object_proxy_state(obj)) proxy_bytes += sizeof(ant_proxy_state_t); + if (ant_object_has_sidecar(obj)) extra_bytes += sizeof(ant_object_sidecar_t); if (obj->exotic_ops) exotic_bytes += sizeof(ant_exotic_ops_t); if (obj->type_tag == T_ARR && obj->u.array.data) array_bytes += obj->u.array.cap * sizeof(ant_value_t); diff --git a/src/modules/formdata.c b/src/modules/formdata.c index f26f6b4..f1b4d27 100644 --- a/src/modules/formdata.c +++ b/src/modules/formdata.c @@ -74,15 +74,10 @@ static ant_value_t get_fd_values(ant_value_t obj) { } static void formdata_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - fd_data_t *d = (fd_data_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - fd_data_free(d); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + fd_data_t *d = (fd_data_t *)(uintptr_t)(size_t)js_getnum(slot->value); + fd_data_free(d); } static bool fd_append_str(fd_data_t *d, const char *name, const char *value) { @@ -412,15 +407,10 @@ static ant_value_t formdata_iter_next(ant_t *js, ant_value_t *args, int nargs) { } static void formdata_iter_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_ITER_STATE && vtype(entries[i].value) == T_NUM) { - fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - free(st); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_ITER_STATE); + if (!slot || vtype(slot->value) != T_NUM) return; + fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(slot->value); + free(st); } static ant_value_t make_formdata_iter(ant_t *js, ant_value_t fd_obj, int kind) { diff --git a/src/modules/string_decoder.c b/src/modules/string_decoder.c index 7b73dff..f67a383 100644 --- a/src/modules/string_decoder.c +++ b/src/modules/string_decoder.c @@ -37,14 +37,10 @@ static sd_state_t *sd_get_state(ant_value_t obj) { } static void sd_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (st) { free(st->td); free(st); } - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(slot->value); + if (st) { free(st->td); free(st); } } static int sd_parse_encoding(const char *s, size_t len) { diff --git a/src/modules/textcodec.c b/src/modules/textcodec.c index b231cf3..fef7037 100644 --- a/src/modules/textcodec.c +++ b/src/modules/textcodec.c @@ -32,14 +32,9 @@ static td_state_t *td_get_state(ant_value_t obj) { } static void td_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((td_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((td_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static int resolve_encoding(const char *s, size_t len) { diff --git a/src/modules/url.c b/src/modules/url.c index 90d4aa8..628eae0 100644 --- a/src/modules/url.c +++ b/src/modules/url.c @@ -49,13 +49,9 @@ void url_free_state(url_state_t *s) { } static void url_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *slots = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (slots[i].slot == SLOT_DATA && vtype(slots[i].value) == T_NUM) { - url_free_state((url_state_t *)(uintptr_t)(size_t)js_getnum(slots[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + url_free_state((url_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static int default_port_for(const char *proto) { diff --git a/src/modules/wasm.c b/src/modules/wasm.c index e53d414..cfb92bb 100644 --- a/src/modules/wasm.c +++ b/src/modules/wasm.c @@ -373,18 +373,17 @@ static ant_value_t wasm_wrap_module(ant_t *js, wasm_store_t *store, wasm_module_ } static void wasm_module_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; - wasm_module_handle_t *handle = (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (!handle) return; - if (handle->module) wasm_module_delete(handle->module); - if (handle->store) wasm_store_delete(handle->store); - free(handle); - return; - } + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + + wasm_module_handle_t *handle = + (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); + + if (!handle) return; + if (handle->module) wasm_module_delete(handle->module); + if (handle->store) wasm_store_delete(handle->store); + + free(handle); } static ant_value_t wasm_wrap_instance(ant_t *js, wasm_instance_handle_t *handle, ant_value_t module_ref) { @@ -397,21 +396,19 @@ static ant_value_t wasm_wrap_instance(ant_t *js, wasm_instance_handle_t *handle, } static void wasm_instance_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; - wasm_instance_handle_t *handle = (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (!handle) return; - for (size_t j = 0; j < handle->host_func_count; j++) { - if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); - } - free(handle->host_funcs); - wasm_extern_vec_delete(&handle->exports); - free(handle); - return; - } + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + + wasm_instance_handle_t *handle = + (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); + + if (!handle) return; + for (size_t j = 0; j < handle->host_func_count; j++) + if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); + + free(handle->host_funcs); + wasm_extern_vec_delete(&handle->exports); + free(handle); } static ant_value_t wasm_wrap_extern_object(ant_t *js, wasm_extern_wrap_kind_t kind, ant_value_t proto, int brand, wasm_store_t *store, bool own_handle, void *ptr, ant_value_t owner) { @@ -438,32 +435,29 @@ static ant_value_t wasm_wrap_extern_object(ant_t *js, wasm_extern_wrap_kind_t ki } static void wasm_extern_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; - wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (!handle) return; - - if (handle->own_handle) { - switch (handle->kind) { - case WASM_EXTERN_WRAP_GLOBAL: - if (handle->as.global) wasm_global_delete(handle->as.global); - break; - case WASM_EXTERN_WRAP_MEMORY: - if (handle->as.memory) wasm_memory_delete(handle->as.memory); - break; - case WASM_EXTERN_WRAP_TABLE: - if (handle->as.table) wasm_table_delete(handle->as.table); - break; - } - if (handle->store) wasm_store_delete(handle->store); - } + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + + wasm_extern_handle_t *handle = + (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); + if (!handle) return; - free(handle); - return; + if (handle->own_handle) { + switch (handle->kind) { + case WASM_EXTERN_WRAP_GLOBAL: + if (handle->as.global) wasm_global_delete(handle->as.global); + break; + case WASM_EXTERN_WRAP_MEMORY: + if (handle->as.memory) wasm_memory_delete(handle->as.memory); + break; + case WASM_EXTERN_WRAP_TABLE: + if (handle->as.table) wasm_table_delete(handle->as.table); + break; + } + if (handle->store) wasm_store_delete(handle->store); } + + free(handle); } static ant_value_t js_wasm_exported_func_call(ant_t *js, ant_value_t *args, int nargs) { diff --git a/src/silver/compiler.c b/src/silver/compiler.c index 7afd9a7..c6c6df5 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -8,6 +8,7 @@ #include "debug.h" #include "tokens.h" #include "runtime.h" +#include "utils.h" #include "ops/coercion.h" #include @@ -345,16 +346,22 @@ static bool private_scope_add( } sv_private_name_t *p = &scope->names[scope->count++]; + + uint64_t hash64 = hash_key(name->str, (size_t)name->len); + uint32_t hash = (uint32_t)(hash64 ^ (hash64 >> 32)); + *p = (sv_private_name_t){ .name = name->str, .len = name->len, .kind = kind, + .hash = hash, .is_static = is_static, .has_getter = kind == SV_COMP_PRIVATE_GETTER, .has_setter = kind == SV_COMP_PRIVATE_SETTER, .owner = NULL, .local = -1 }; + return true; } @@ -4655,7 +4662,8 @@ void compile_class(sv_compiler_t *c, sv_ast_t *node) { sv_private_name_t *p = &private_scope.names[i]; p->owner = c; p->local = add_local(c, "", 0, true, c->scope_depth); - emit_op(c, OP_OBJECT); + emit_op(c, OP_PRIVATE_TOKEN); + emit_u32(c, p->hash); emit_put_local(c, p->local); } } diff --git a/src/silver/engine.c b/src/silver/engine.c index 8a3f56d..52b7bb2 100644 --- a/src/silver/engine.c +++ b/src/silver/engine.c @@ -965,8 +965,9 @@ ant_value_t sv_execute_frame(sv_vm_t *vm, sv_func_t *func, ant_value_t this, ant L_ARRAY: { sv_op_array(vm, js, ip); NEXT(3); } L_SET_BRAND: { sv_op_set_brand(vm, ip); NEXT(2); } - L_REGEXP: { sv_op_regexp(vm, js); NEXT(1); } - L_CLOSURE: { VM_CHECK(sv_op_closure(vm, js, frame, func, ip)); NEXT(5); } + L_REGEXP: { sv_op_regexp(vm, js); NEXT(1); } + L_CLOSURE: { VM_CHECK(sv_op_closure(vm, js, frame, func, ip)); NEXT(5); } + L_PRIVATE_TOKEN: { sv_op_private_token(vm, js, ip); NEXT(5); } L_POP: { sv_op_pop(vm); NEXT(1); } L_DUP: { sv_op_dup(vm); NEXT(1); } diff --git a/src/silver/ops/literals.h b/src/silver/ops/literals.h index dd8b457..61e7649 100644 --- a/src/silver/ops/literals.h +++ b/src/silver/ops/literals.h @@ -75,6 +75,13 @@ static inline void sv_op_object(sv_vm_t *vm, ant_t *js, sv_func_t *func, uint8_t vm->stack[vm->sp++] = obj; } +static inline void sv_op_private_token(sv_vm_t *vm, ant_t *js, uint8_t *ip) { + ant_value_t obj = mkobj(js, 0); + uint32_t hash = sv_get_u32(ip + 1); + js_set_slot(obj, SLOT_DATA, js_mknum((double)hash)); + vm->stack[vm->sp++] = obj; +} + static inline void sv_op_array(sv_vm_t *vm, ant_t *js, uint8_t *ip) { uint16_t n = sv_get_u16(ip + 1); ant_value_t arr = js_mkarr(js); diff --git a/src/silver/ops/private.h b/src/silver/ops/private.h index c2935a9..7224e2a 100644 --- a/src/silver/ops/private.h +++ b/src/silver/ops/private.h @@ -1,8 +1,10 @@ #ifndef SV_PRIVATE_H #define SV_PRIVATE_H +#include +#include "gc.h" +#include "object.h" #include "silver/engine.h" -#include enum { SV_PRIVATE_FIELD = 0, @@ -12,91 +14,161 @@ enum { SV_PRIVATE_SETTER = 4 }; -static inline ant_value_t sv_private_entry_get(ant_t *js, ant_value_t entry, ant_offset_t idx) { - return vtype(entry) == T_ARR - ? js_arr_get(js, entry, idx) - : js_mkundef(); -} +static inline uint32_t sv_private_hash_token(ant_value_t token) { + if (is_object_type(token)) { + ant_value_t cached = js_get_slot(token, SLOT_DATA); + if (vtype(cached) == T_NUM) return (uint32_t)js_getnum(cached); + } -static inline ant_value_t sv_private_entry_set(ant_t *js, ant_value_t entry, ant_offset_t idx, ant_value_t value) { - char key_buf[8]; - int key_len = snprintf(key_buf, sizeof(key_buf), "%u", (unsigned)idx); - return js_setprop(js, entry, js_mkstr(js, key_buf, (size_t)key_len), value); + uint64_t x = token ^ (token >> 33); + x *= 0xff51afd7ed558ccdULL; + x ^= x >> 33; + x *= 0xc4ceb9fe1a85ec53ULL; + x ^= x >> 33; + + return (uint32_t)x; } -static inline ant_value_t sv_private_table(ant_t *js, ant_value_t obj, bool create) { - if (!is_object_type(obj)) return js_mkundef(); - ant_value_t table = js_get_slot(obj, SLOT_PRIVATE_ELEMENTS); - - if (vtype(table) == T_ARR) return table; - if (!create) return js_mkundef(); - table = js_mkarr(js); - - if (is_err(table)) return table; - js_set_slot_wb(js, obj, SLOT_PRIVATE_ELEMENTS, table); - - return table; +static inline ant_private_table_t *sv_private_table_for_obj(ant_value_t obj, bool create) { + if (!is_object_type(obj)) return NULL; + ant_object_t *ptr = js_obj_ptr(js_as_obj(obj)); + if (!ptr) return NULL; + ant_object_sidecar_t *sidecar = create ? ant_object_ensure_sidecar(ptr) : ant_object_sidecar(ptr); + return sidecar ? &sidecar->private_table : NULL; } -static inline ant_value_t sv_private_cached_entry( - ant_t *js, ant_value_t table, ant_value_t token, ant_offset_t len +static inline uint32_t sv_private_find_slot( + ant_private_table_t *table, ant_value_t token, uint32_t hash, bool *found ) { - if (!is_object_type(token)) return js_mkundef(); - ant_value_t cached = js_get_slot(token, SLOT_DATA); - if (vtype(cached) != T_NUM) return js_mkundef(); + uint32_t mask = table->cap - 1; + uint32_t idx = hash & mask; + + for (;;) { + ant_private_entry_t *entry = &table->entries[idx]; + if (!entry->occupied) { + *found = false; + return idx; + } + + if (entry->hash == hash && entry->token == token) { + *found = true; + return idx; + } + + idx = (idx + 1) & mask; + } +} - double idx_num = js_getnum(cached); - if (idx_num < 0 || idx_num >= (double)len) return js_mkundef(); +static inline bool sv_private_table_grow(ant_private_table_t *table) { + uint32_t old_cap = table->cap; + uint32_t new_cap = old_cap ? old_cap * 2 : 8; + + ant_private_entry_t *new_entries = + (ant_private_entry_t *)calloc(new_cap, sizeof(*new_entries)); + if (!new_entries) return false; + + ant_private_entry_t *old_entries = table->entries; + table->entries = new_entries; + table->cap = new_cap; + table->count = 0; + + for (uint32_t i = 0; i < old_cap; i++) { + ant_private_entry_t entry = old_entries[i]; + if (!entry.occupied) continue; + + bool found = false; + uint32_t slot = sv_private_find_slot( + table, entry.token, + entry.hash, &found + ); + + table->entries[slot] = entry; + table->count++; + } - ant_offset_t idx = (ant_offset_t)idx_num; - ant_value_t entry = js_arr_get(js, table, idx); - if (vtype(entry) == T_ARR && sv_private_entry_get(js, entry, 0) == token) - return entry; - return js_mkundef(); + free(old_entries); + return true; } -static inline void sv_private_cache_entry(ant_t *js, ant_value_t token, ant_offset_t idx) { - if (is_object_type(token)) - js_set_slot(token, SLOT_DATA, js_mknum((double)idx)); +static inline ant_private_entry_t *sv_private_find_entry(ant_value_t obj, ant_value_t token) { + ant_private_table_t *table = sv_private_table_for_obj(obj, false); + if (!table || !table->entries || table->cap == 0) return NULL; + + bool found = false; + uint32_t hash = sv_private_hash_token(token); + uint32_t slot = sv_private_find_slot(table, token, hash, &found); + + return found ? &table->entries[slot] : NULL; } -static inline ant_value_t sv_private_find_entry(ant_t *js, ant_value_t obj, ant_value_t token) { - ant_value_t table = sv_private_table(js, obj, false); - if (vtype(table) != T_ARR) return js_mkundef(); - ant_offset_t len = js_arr_len(js, table); +static inline ant_value_t sv_private_entry_get(ant_private_entry_t *entry, ant_offset_t idx) { + if (!entry) return js_mkundef(); + + switch (idx) { + case 0: return entry->token; + case 1: return js_mknum((double)entry->kind); + case 2: return entry->value; + case 3: return entry->getter; + case 4: return entry->setter; + default: return js_mkundef(); + } +} - ant_value_t cached = sv_private_cached_entry(js, table, token, len); - if (vtype(cached) != T_UNDEF) return cached; +static inline ant_value_t sv_private_entry_set( + ant_t *js, ant_value_t obj, ant_private_entry_t *entry, ant_offset_t idx, ant_value_t value +) { + if (!entry) return js_mkundef(); + + switch (idx) { + case 2: entry->value = value; break; + case 3: entry->getter = value; break; + case 4: entry->setter = value; break; + default: return js_mkundef(); + } - for (ant_offset_t i = 0; i < len; i++) { - ant_value_t entry = js_arr_get(js, table, i); - if (vtype(entry) == T_ARR && sv_private_entry_get(js, entry, 0) == token) { - sv_private_cache_entry(js, token, i); - return entry; - }} + ant_object_t *ptr = is_object_type(obj) ? js_obj_ptr(js_as_obj(obj)) : NULL; + if (ptr) gc_write_barrier(js, ptr, value); return js_mkundef(); } -static inline ant_value_t sv_private_make_entry( +static inline ant_private_entry_t *sv_private_make_entry( ant_t *js, ant_value_t obj, ant_value_t token, int kind, ant_value_t value, ant_value_t getter, ant_value_t setter ) { - ant_value_t table = sv_private_table(js, obj, true); - if (is_err(table)) return table; - - ant_value_t entry = js_mkarr(js); - if (is_err(entry)) return entry; - js_arr_push(js, entry, token); - js_arr_push(js, entry, js_mknum((double)kind)); - js_arr_push(js, entry, value); - js_arr_push(js, entry, getter); - js_arr_push(js, entry, setter); + ant_private_table_t *table = sv_private_table_for_obj(obj, true); + if (!table) return NULL; - ant_offset_t idx = js_arr_len(js, table); - js_arr_push(js, table, entry); - sv_private_cache_entry(js, token, idx); + if (table->cap == 0 || ((table->count + 1) * 4 >= table->cap * 3)) { + if (!sv_private_table_grow(table)) return NULL; + } + + bool found = false; + uint32_t hash = sv_private_hash_token(token); + uint32_t slot = sv_private_find_slot(table, token, hash, &found); + ant_private_entry_t *entry = &table->entries[slot]; + if (!found) { + *entry = (ant_private_entry_t){ + .token = token, + .value = value, + .getter = getter, + .setter = setter, + .hash = hash, + .kind = (uint8_t)kind, + .occupied = 1 + }; + table->count++; + } + + ant_object_t *ptr = js_obj_ptr(js_as_obj(obj)); + if (ptr) { + gc_write_barrier(js, ptr, token); + gc_write_barrier(js, ptr, value); + gc_write_barrier(js, ptr, getter); + gc_write_barrier(js, ptr, setter); + } + return entry; } @@ -116,13 +188,16 @@ static inline ant_value_t sv_op_get_private_impl(sv_vm_t *vm, ant_t *js, bool op return sv_private_missing(js); } - ant_value_t entry = sv_private_find_entry(js, obj, token); - if (vtype(entry) == T_UNDEF) return sv_private_missing(js); + ant_private_entry_t *entry = sv_private_find_entry(obj, token); + if (!entry) return sv_private_missing(js); - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); - int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; + ant_value_t kind_val = sv_private_entry_get(entry, 1); + int kind = vtype(kind_val) == T_NUM + ? (int)js_getnum(kind_val) + : SV_PRIVATE_FIELD; + if (kind == SV_PRIVATE_ACCESSOR) { - ant_value_t getter = sv_private_entry_get(js, entry, 3); + ant_value_t getter = sv_private_entry_get(entry, 3); if (vtype(getter) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "Private accessor has no getter"); ant_value_t result = sv_vm_call_explicit_this(vm, js, getter, obj, NULL, 0); @@ -131,7 +206,7 @@ static inline ant_value_t sv_op_get_private_impl(sv_vm_t *vm, ant_t *js, bool op return js_mkundef(); } - vm->stack[vm->sp++] = sv_private_entry_get(js, entry, 2); + vm->stack[vm->sp++] = sv_private_entry_get(entry, 2); return js_mkundef(); } @@ -149,20 +224,20 @@ static inline ant_value_t sv_op_put_private(sv_vm_t *vm, ant_t *js) { ant_value_t obj = vm->stack[--vm->sp]; if (!is_object_type(obj)) return sv_private_missing(js); - ant_value_t entry = sv_private_find_entry(js, obj, token); - if (vtype(entry) == T_UNDEF) return sv_private_missing(js); + ant_private_entry_t *entry = sv_private_find_entry(obj, token); + if (!entry) return sv_private_missing(js); - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); + ant_value_t kind_val = sv_private_entry_get(entry, 1); int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; if (kind == SV_PRIVATE_FIELD) { - ant_value_t set = sv_private_entry_set(js, entry, 2, val); + ant_value_t set = sv_private_entry_set(js, obj, entry, 2, val); if (is_err(set)) return set; vm->stack[vm->sp++] = val; return js_mkundef(); } if (kind == SV_PRIVATE_ACCESSOR) { - ant_value_t setter = sv_private_entry_get(js, entry, 4); + ant_value_t setter = sv_private_entry_get(entry, 4); if (vtype(setter) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "Private accessor has no setter"); ant_value_t args[1] = { val }; @@ -182,46 +257,49 @@ static inline ant_value_t sv_op_def_private(sv_vm_t *vm, ant_t *js, uint8_t *ip) ant_value_t obj = vm->stack[vm->sp - 1]; if (!is_object_type(obj)) return sv_private_missing(js); - ant_value_t existing = sv_private_find_entry(js, obj, token); + ant_private_entry_t *existing = sv_private_find_entry(obj, token); if (def_kind == SV_PRIVATE_GETTER || def_kind == SV_PRIVATE_SETTER) { - ant_value_t entry = existing; - if (vtype(entry) == T_UNDEF) { + ant_private_entry_t *entry = existing; + if (!entry) { entry = sv_private_make_entry( js, obj, token, SV_PRIVATE_ACCESSOR, js_mkundef(), def_kind == SV_PRIVATE_GETTER ? val : js_mkundef(), def_kind == SV_PRIVATE_SETTER ? val : js_mkundef()); - return is_err(entry) ? entry : js_mkundef(); + return entry ? js_mkundef() : js_mkerr(js, "oom"); } - - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); + + ant_value_t kind_val = sv_private_entry_get(entry, 1); int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; if (kind != SV_PRIVATE_ACCESSOR) return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot redefine private member"); - + ant_offset_t slot = def_kind == SV_PRIVATE_GETTER ? 3 : 4; - if (vtype(sv_private_entry_get(js, entry, slot)) != T_UNDEF) + if (vtype(sv_private_entry_get(entry, slot)) != T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot redefine private accessor"); - return sv_private_entry_set(js, entry, slot, val); + return sv_private_entry_set(js, obj, entry, slot, val); } - if (vtype(existing) != T_UNDEF) + if (existing) return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot initialize private member twice"); - ant_value_t entry = sv_private_make_entry( + ant_private_entry_t *entry = sv_private_make_entry( js, obj, token, def_kind == SV_PRIVATE_METHOD ? SV_PRIVATE_METHOD : SV_PRIVATE_FIELD, val, js_mkundef(), js_mkundef()); - return is_err(entry) ? entry : js_mkundef(); + + return entry ? js_mkundef() : js_mkerr(js, "oom"); } static inline ant_value_t sv_op_has_private(sv_vm_t *vm, ant_t *js) { ant_value_t token = vm->stack[--vm->sp]; ant_value_t obj = vm->stack[--vm->sp]; + if (!is_object_type(obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "Right operand of private brand check must be an object"); - vm->stack[vm->sp++] = js_bool(vtype(sv_private_find_entry(js, obj, token)) != T_UNDEF); + vm->stack[vm->sp++] = js_bool(sv_private_find_entry(obj, token) != NULL); + return js_mkundef(); } diff --git a/src/streams/codec.c b/src/streams/codec.c index dd4f2ca..913a984 100644 --- a/src/streams/codec.c +++ b/src/streams/codec.c @@ -58,23 +58,15 @@ ant_value_t tds_stream_writable(ant_value_t obj) { } static void tes_state_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((tes_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((tes_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static void tds_state_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((td_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((td_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static ant_value_t codec_transform_controller(ant_value_t *args, int nargs) { diff --git a/src/streams/compression.c b/src/streams/compression.c index 2dc5f7a..0f21b17 100644 --- a/src/streams/compression.c +++ b/src/streams/compression.c @@ -83,40 +83,27 @@ ant_value_t ds_stream_writable(ant_value_t obj) { } static void zstate_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (st->initialized) deflateEnd(&st->strm); - free(st); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(slot->value); + if (st->initialized) deflateEnd(&st->strm); + free(st); } static void zstate_inflate_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - if (st->initialized) inflateEnd(&st->strm); - free(st); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(slot->value); + if (st->initialized) inflateEnd(&st->strm); + free(st); } static void brotli_state_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - brotli_stream_state_t *st = - (brotli_stream_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - brotli_stream_state_destroy(st); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + brotli_stream_state_t *st = + (brotli_stream_state_t *)(uintptr_t)(size_t)js_getnum(slot->value); + brotli_stream_state_destroy(st); } static ant_value_t enqueue_buffer(ant_t *js, ant_value_t ctrl_obj, const uint8_t *data, size_t len) { diff --git a/src/streams/pipes.c b/src/streams/pipes.c index 62f09e5..197051c 100644 --- a/src/streams/pipes.c +++ b/src/streams/pipes.c @@ -46,13 +46,9 @@ static void pipes_chain_promise( } static void pipe_state_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((pipe_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((pipe_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static pipe_state_t *pipe_get_state(ant_value_t state) { @@ -487,13 +483,9 @@ typedef struct { } tee_state_t; static void tee_state_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((tee_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((tee_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static tee_state_t *tee_get_state(ant_value_t state) { diff --git a/src/streams/readable.c b/src/streams/readable.c index b8099fc..f452e82 100644 --- a/src/streams/readable.c +++ b/src/streams/readable.c @@ -61,25 +61,18 @@ rs_controller_t *rs_get_controller(ant_value_t obj) { } static void rs_stream_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static void rs_controller_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - free(ctrl->queue_sizes); - free(ctrl); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + rs_controller_t *ctrl = + (rs_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); + free(ctrl->queue_sizes); + free(ctrl); } ant_value_t rs_stream_controller(ant_t *js, ant_value_t stream_obj) { diff --git a/src/streams/transform.c b/src/streams/transform.c index 552f684..771b168 100644 --- a/src/streams/transform.c +++ b/src/streams/transform.c @@ -54,47 +54,33 @@ ant_value_t ts_stream_writable(ant_value_t ts_obj) { } static void ts_ws_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static void ts_ws_ctrl_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - free(ctrl->queue_sizes); - free(ctrl); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + ws_controller_t *ctrl = + (ws_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); + free(ctrl->queue_sizes); + free(ctrl); } static void ts_rs_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static void ts_rs_ctrl_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - free(ctrl->queue_sizes); - free(ctrl); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + rs_controller_t *ctrl = + (rs_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); + free(ctrl->queue_sizes); + free(ctrl); } static inline bool ts_get_backpressure(ant_value_t ts_obj) { diff --git a/src/streams/writable.c b/src/streams/writable.c index df6f9fc..dbe3b83 100644 --- a/src/streams/writable.c +++ b/src/streams/writable.c @@ -49,25 +49,18 @@ ws_controller_t *ws_get_controller(ant_value_t obj) { } static void ws_stream_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); } static void ws_controller_finalize(ant_t *js, ant_object_t *obj) { - if (!obj->extra_slots) return; - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; - for (uint8_t i = 0; i < obj->extra_count; i++) { - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { - ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); - free(ctrl->queue_sizes); - free(ctrl); - return; - }} + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); + if (!slot || vtype(slot->value) != T_NUM) return; + ws_controller_t *ctrl = + (ws_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); + free(ctrl->queue_sizes); + free(ctrl); } ant_value_t ws_stream_controller(ant_value_t stream_obj) {