MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

regression fix: allocation pressure reduction

migrate extra slots to multiplex to reduce object size from 176bytes to 160 bytes

+529 -370
+112 -11
include/object.h
··· 9 9 #include <stdbool.h> 10 10 #include <stddef.h> 11 11 #include <stdint.h> 12 + #include <stdlib.h> 12 13 13 14 typedef struct { 14 15 ant_value_t (*getter)(ant_t *, ant_value_t, const char *, size_t); ··· 43 44 bool revoked; 44 45 } ant_proxy_state_t; 45 46 47 + typedef struct { 48 + uint8_t slot; 49 + ant_value_t value; 50 + } ant_extra_slot_t; 51 + 52 + typedef struct { 53 + ant_value_t token; 54 + ant_value_t value; 55 + ant_value_t getter; 56 + ant_value_t setter; 57 + 58 + uint32_t hash; 59 + uint8_t kind; 60 + uint8_t occupied; 61 + } ant_private_entry_t; 62 + 63 + typedef struct { 64 + ant_private_entry_t *entries; 65 + uint32_t count; 66 + uint32_t cap; 67 + } ant_private_table_t; 68 + 69 + typedef struct { 70 + ant_extra_slot_t *extra_slots; 71 + ant_private_table_t private_table; 72 + ant_proxy_state_t *proxy_state; 73 + 74 + uint8_t extra_count; 75 + uint8_t flags; 76 + } ant_object_sidecar_t; 77 + 78 + typedef struct ant_prop_ref { 79 + ant_object_t *obj; 80 + uint32_t slot; 81 + bool valid; 82 + } ant_prop_ref_t; 83 + 46 84 typedef struct ant_object { 47 85 struct ant_object *next; 48 86 ··· 54 92 ant_value_t (*exotic_keys)(ant_t *, ant_value_t); 55 93 56 94 ant_promise_state_t *promise_state; 57 - ant_proxy_state_t *proxy_state; 58 - ant_value_t *extra_slots; 95 + ant_extra_slot_t *extra_slots; 59 96 60 97 struct ant_object *gc_pending_next; 61 98 void (*finalizer)(ant_t *, struct ant_object *); ··· 96 133 uint8_t overflow_cap; 97 134 } ant_object_t; 98 135 99 - typedef struct { 100 - uint8_t slot; 101 - ant_value_t value; 102 - } ant_extra_slot_t; 136 + static inline bool ant_object_has_sidecar(const ant_object_t *obj) { 137 + return obj && (((uintptr_t)obj->extra_slots & ant_sidecar) != 0); 138 + } 139 + 140 + static inline ant_object_sidecar_t *ant_object_sidecar(const ant_object_t *obj) { 141 + if (!ant_object_has_sidecar(obj)) return NULL; 142 + return (ant_object_sidecar_t *)((uintptr_t)obj->extra_slots & ~ant_sidecar); 143 + } 144 + 145 + static inline ant_extra_slot_t *ant_object_extra_slots_ptr(const ant_object_t *obj) { 146 + if (!obj) return NULL; 147 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 148 + return sidecar ? sidecar->extra_slots : obj->extra_slots; 149 + } 150 + 151 + static inline uint8_t ant_object_extra_count(const ant_object_t *obj) { 152 + if (!obj) return 0; 153 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 154 + return sidecar ? sidecar->extra_count : obj->extra_count; 155 + } 156 + 157 + static inline ant_extra_slot_t *ant_object_extra_slots(const ant_object_t *obj, uint8_t *count) { 158 + if (!obj) { 159 + if (count) *count = 0; 160 + return NULL; 161 + } 162 + 163 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 164 + if (sidecar) { 165 + if (count) *count = sidecar->extra_count; 166 + return sidecar->extra_slots; 167 + } 168 + 169 + if (count) *count = obj->extra_count; 170 + return obj->extra_slots; 171 + } 172 + 173 + static inline ant_extra_slot_t *ant_object_extra_slot(const ant_object_t *obj, uint8_t slot) { 174 + uint8_t count = 0; 175 + ant_extra_slot_t *entries = ant_object_extra_slots(obj, &count); 176 + 177 + for (uint8_t i = 0; i < count; i++) 178 + if (entries[i].slot == slot) return &entries[i]; 179 + 180 + return NULL; 181 + } 182 + 183 + static inline ant_object_sidecar_t *ant_object_ensure_sidecar(ant_object_t *obj) { 184 + if (!obj) return NULL; 185 + 186 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 187 + if (sidecar) return sidecar; 103 188 104 - typedef struct ant_prop_ref { 105 - ant_object_t *obj; 106 - uint32_t slot; 107 - bool valid; 108 - } ant_prop_ref_t; 189 + sidecar = (ant_object_sidecar_t *)calloc(1, sizeof(*sidecar)); 190 + if (!sidecar) return NULL; 191 + 192 + sidecar->extra_slots = obj->extra_slots; 193 + sidecar->extra_count = obj->extra_count; 194 + 195 + obj->extra_slots = (ant_extra_slot_t *)((uintptr_t)sidecar | ant_sidecar); 196 + obj->extra_count = 0; 197 + 198 + return sidecar; 199 + } 200 + 201 + static inline ant_proxy_state_t *ant_object_proxy_state(const ant_object_t *obj) { 202 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 203 + return sidecar ? sidecar->proxy_state : NULL; 204 + } 205 + 206 + static inline ant_private_table_t *ant_object_private_table(const ant_object_t *obj) { 207 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 208 + return sidecar ? (ant_private_table_t *)&sidecar->private_table : NULL; 209 + } 109 210 110 211 static inline uint32_t ant_object_inobj_limit(const ant_object_t *obj) { 111 212 if (!obj) return ANT_INOBJ_MAX_SLOTS;
+3 -1
include/shapes.h
··· 36 36 ant_shape_t *ant_shape_new(void); 37 37 ant_shape_t *ant_shape_new_with_inobj_limit(uint8_t inobj_limit); 38 38 ant_shape_t *ant_shape_clone(const ant_shape_t *shape); 39 + 39 40 bool ant_shape_is_shared(const ant_shape_t *shape); 40 41 void ant_shape_retain(ant_shape_t *shape); 41 42 void ant_shape_release(ant_shape_t *shape); ··· 52 53 bool ant_shape_remove_slot(ant_shape_t *shape, uint32_t slot, uint32_t *swapped_from); 53 54 54 55 uint32_t ant_shape_count(const ant_shape_t *shape); 56 + uint8_t ant_shape_get_attrs(const ant_shape_t *shape, uint32_t slot); 57 + 55 58 const ant_shape_prop_t *ant_shape_prop_at(const ant_shape_t *shape, uint32_t slot); 56 59 ant_shape_prop_t *ant_shape_prop_mut_at(ant_shape_t *shape, uint32_t slot); 57 60 58 61 bool ant_shape_set_attrs_interned(ant_shape_t *shape, const char *interned, uint8_t attrs); 59 62 bool ant_shape_set_attrs_symbol(ant_shape_t *shape, ant_offset_t sym_off, uint8_t attrs); 60 - uint8_t ant_shape_get_attrs(const ant_shape_t *shape, uint32_t slot); 61 63 bool ant_shape_clear_accessor_slot(ant_shape_t *shape, uint32_t slot); 62 64 63 65 void ant_gc_shapes_begin(void);
+1
include/silver/compiler.h
··· 72 72 const char *name; 73 73 uint32_t len; 74 74 uint8_t kind; 75 + uint32_t hash; 75 76 bool is_static; 76 77 bool has_getter; 77 78 bool has_setter;
+1
include/silver/opcode.h
··· 37 37 OP_DEF( THIS, 1, 0, 1, none) /* push current 'this' */ 38 38 OP_DEF( GLOBAL, 1, 0, 1, none) /* push 'globalThis' (js->global) */ 39 39 OP_DEF( OBJECT, 1, 0, 1, none) /* push empty object {} */ 40 + OP_DEF( PRIVATE_TOKEN, 5, 0, 1, u32) /* push private-name token with cached hash */ 40 41 OP_DEF( ARRAY, 3, 0, 1, npop) /* push array from stack items */ 41 42 OP_DEF( SET_BRAND, 2, 1, 1, u8) /* obj -> obj (brand id) */ 42 43 OP_DEF( REGEXP, 1, 2, 1, none) /* pattern flags -> regexp */
+1
include/types.h
··· 37 37 uint8_t flags; 38 38 } ant_cfunc_meta_t; 39 39 40 + #define ant_sidecar ((uintptr_t)1u) 40 41 #define ant_bind_t ant_value_t func, ant_value_t this_val 41 42 #define ant_params_t ant_t *js, ant_value_t *args, int nargs 42 43
+65 -35
src/ant.c
··· 240 240 if (obj) obj->is_constructor = is_constructor ? 1u : 0u; 241 241 } 242 242 243 - static inline ant_extra_slot_t *obj_extra_slots(ant_object_t *obj) { 244 - return (ant_extra_slot_t *)obj->extra_slots; 245 - } 246 - 247 243 static ant_value_t obj_extra_get(ant_object_t *obj, internal_slot_t slot) { 248 - if (!obj || obj->extra_count == 0) return js_mkundef(); 249 - ant_extra_slot_t *entries = obj_extra_slots(obj); 250 - for (uint8_t i = 0; i < obj->extra_count; i++) { 251 - if ((internal_slot_t)entries[i].slot == slot) return entries[i].value; 252 - } 253 - return js_mkundef(); 244 + ant_extra_slot_t *entry = ant_object_extra_slot(obj, (uint8_t)slot); 245 + return entry ? entry->value : js_mkundef(); 254 246 } 255 247 256 248 static bool obj_extra_set(ant_object_t *obj, internal_slot_t slot, ant_value_t value) { 257 249 if (!obj) return false; 258 - ant_extra_slot_t *entries = obj_extra_slots(obj); 259 - for (uint8_t i = 0; i < obj->extra_count; i++) { 260 - if ((internal_slot_t)entries[i].slot == slot) { 261 - entries[i].value = value; 262 - return true; 263 - } 250 + 251 + ant_extra_slot_t *entry = ant_object_extra_slot(obj, (uint8_t)slot); 252 + if (entry) { 253 + entry->value = value; 254 + return true; 264 255 } 265 - 266 - if (obj->extra_count == UINT8_MAX) return false; 267 - uint8_t next_count = (uint8_t)(obj->extra_count + 1); 256 + 257 + uint8_t count = 0; 258 + ant_extra_slot_t *entries = ant_object_extra_slots(obj, &count); 259 + 260 + if (count == UINT8_MAX) return false; 261 + uint8_t next_count = (uint8_t)(count + 1); 262 + 268 263 ant_extra_slot_t *next = realloc(entries, sizeof(*next) * next_count); 269 264 if (!next) return false; 270 265 271 - next[obj->extra_count].slot = (uint8_t)slot; 272 - next[obj->extra_count].value = value; 273 - obj->extra_slots = (ant_value_t *)next; 274 - obj->extra_count = next_count; 266 + next[count].slot = (uint8_t)slot; 267 + next[count].value = value; 268 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 269 + 270 + if (sidecar) { 271 + sidecar->extra_slots = next; 272 + sidecar->extra_count = next_count; 273 + } else { 274 + obj->extra_slots = next; 275 + obj->extra_count = next_count; 276 + } 277 + 275 278 return true; 276 279 } 277 280 ··· 403 406 404 407 obj->type_tag = type_tag; 405 408 obj->proto = js_mkundef(); 409 + obj->u.data.value = js_mkundef(); 410 + 406 411 obj->shape = ant_shape_new_with_inobj_limit(inobj_limit); 412 + if (!obj->shape) { 413 + obj->mark_epoch = ANT_GC_DEAD; 414 + fixed_arena_free_elem(&js->obj_arena, obj); 415 + return NULL; 416 + } 417 + obj->inobj_limit = ant_shape_get_inobj_limit(obj->shape); 418 + 407 419 obj->overflow_prop = NULL; 408 420 obj->overflow_cap = 0; 409 421 obj->prop_count = 0; 410 - obj->inobj_limit = ant_shape_get_inobj_limit(obj->shape); 411 - for (uint32_t i = 0; i < ANT_INOBJ_MAX_SLOTS; i++) obj->inobj[i] = js_mkundef(); 412 - obj->extensible = 1; 413 - obj->frozen = 0; 414 - obj->sealed = 0; 415 - obj->is_exotic = 0; 416 - obj->is_constructor = 0; 417 - obj->fast_array = 0; 422 + obj->propref_count = 0; 423 + 424 + for (uint32_t i = 0; i < ANT_INOBJ_MAX_SLOTS; i++) 425 + obj->inobj[i] = js_mkundef(); 426 + 418 427 obj->exotic_ops = NULL; 419 428 obj->exotic_keys = NULL; 420 429 obj->promise_state = NULL; 421 - obj->proxy_state = NULL; 422 - obj->u.data.value = js_mkundef(); 423 430 obj->extra_slots = NULL; 424 431 obj->extra_count = 0; 432 + 433 + obj->finalizer = NULL; 425 434 obj->gc_pending_next = NULL; 426 435 obj->gc_pending_rooted = false; 436 + 437 + obj->native.ptr = NULL; 438 + obj->native.tag = 0; 439 + 440 + obj->mark_epoch = 0; 441 + obj->extensible = 1; 442 + obj->frozen = 0; 443 + obj->sealed = 0; 444 + obj->is_exotic = 0; 445 + obj->is_constructor = 0; 446 + obj->fast_array = 0; 447 + obj->may_have_holes = 0; 448 + obj->may_have_dense_elements = 0; 449 + obj->gc_permanent = 0; 427 450 obj->generation = 0; 428 451 obj->in_remember_set = 0; 429 452 ··· 13794 13817 static ant_proxy_state_t *get_proxy_data(ant_value_t obj) { 13795 13818 if (vtype(obj) != T_OBJ) return NULL; 13796 13819 ant_object_t *ptr = js_obj_ptr(obj); 13797 - return ptr ? ptr->proxy_state : NULL; 13820 + return ptr ? ant_object_proxy_state(ptr) : NULL; 13798 13821 } 13799 13822 13800 13823 bool is_proxy(ant_value_t obj) { ··· 14332 14355 14333 14356 proxy_ptr->is_exotic = 1; 14334 14357 js_mark_constructor(proxy_obj, js_is_constructor(target)); 14335 - proxy_ptr->proxy_state = data; 14358 + 14359 + ant_object_sidecar_t *sidecar = ant_object_ensure_sidecar(proxy_ptr); 14360 + if (!sidecar) { 14361 + free(data); 14362 + return js_mkerr(js, "out of memory"); 14363 + } 14364 + 14365 + sidecar->proxy_state = data; 14336 14366 return proxy_obj; 14337 14367 } 14338 14368
+29 -12
src/gc/objects.c
··· 266 266 uint32_t count = ant_shape_count(obj->shape); 267 267 for (uint32_t i = 0; i < count && i < obj->prop_count; i++) 268 268 gc_mark_value(js, ant_object_prop_get_unchecked(obj, i)); 269 + 269 270 for (uint32_t i = 0; i < count; i++) { 270 271 const ant_shape_prop_t *prop = ant_shape_prop_at(obj->shape, i); 271 272 if (prop && prop->has_getter) gc_mark_value(js, prop->getter); 272 273 if (prop && prop->has_setter) gc_mark_value(js, prop->setter); 273 274 }} 274 275 275 - if (obj->extra_slots) { 276 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 277 - for (uint8_t i = 0; i < obj->extra_count; i++) gc_mark_value(js, entries[i].value); 276 + uint8_t extra_count = 0; 277 + ant_extra_slot_t *extra_slots = ant_object_extra_slots(obj, &extra_count); 278 + if (extra_slots) { 279 + for (uint8_t i = 0; i < extra_count; i++) gc_mark_value(js, extra_slots[i].value); 278 280 } 279 281 280 282 if (obj->type_tag == T_ARR && obj->u.array.data) { ··· 289 291 gc_mark_promise_handlers(js, pd); 290 292 } 291 293 292 - if (obj->proxy_state) { 293 - gc_mark_value(js, obj->proxy_state->target); 294 - gc_mark_value(js, obj->proxy_state->handler); 294 + ant_proxy_state_t *proxy_state = ant_object_proxy_state(obj); 295 + if (proxy_state) { 296 + gc_mark_value(js, proxy_state->target); 297 + gc_mark_value(js, proxy_state->handler); 298 + } 299 + 300 + ant_private_table_t *table = ant_object_private_table(obj); 301 + if (table && table->entries) for (uint32_t i = 0; i < table->cap; i++) { 302 + ant_private_entry_t *entry = &table->entries[i]; 303 + if (!entry->occupied) continue; 304 + gc_mark_value(js, entry->token); 305 + gc_mark_value(js, entry->value); 306 + gc_mark_value(js, entry->getter); 307 + gc_mark_value(js, entry->setter); 295 308 } 296 309 297 310 gc_mark_abort_signal_object( ··· 540 553 obj->shape = NULL; 541 554 } 542 555 543 - if (obj->extra_slots) { 556 + if (ant_object_has_sidecar(obj)) { 557 + ant_object_sidecar_t *sidecar = ant_object_sidecar(obj); 558 + free(sidecar->extra_slots); 559 + free(sidecar->proxy_state); 560 + free(sidecar->private_table.entries); 561 + free(sidecar); 562 + obj->extra_slots = NULL; 563 + } 564 + 565 + else if (obj->extra_slots) { 544 566 free(obj->extra_slots); 545 567 obj->extra_slots = NULL; 546 568 } ··· 553 575 utarray_free(obj->promise_state->handlers); 554 576 free(obj->promise_state); 555 577 obj->promise_state = NULL; 556 - } 557 - 558 - if (obj->proxy_state) { 559 - free(obj->proxy_state); 560 - obj->proxy_state = NULL; 561 578 } 562 579 563 580 if (obj->type_tag == T_ARR && obj->u.array.data) {
+4 -8
src/modules/blob.c
··· 150 150 } 151 151 152 152 static void blob_finalize(ant_t *js, ant_object_t *obj) { 153 - if (!obj->extra_slots) return; 154 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 155 - for (uint8_t i = 0; i < obj->extra_count; i++) { 156 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 157 - blob_data_t *bd = (blob_data_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 158 - if (bd) { free(bd->data); free(bd->type); free(bd->name); free(bd); } 159 - return; 160 - }} 153 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 154 + if (!slot || vtype(slot->value) != T_NUM) return; 155 + blob_data_t *bd = (blob_data_t *)(uintptr_t)(size_t)js_getnum(slot->value); 156 + if (bd) { free(bd->data); free(bd->type); free(bd->name); free(bd); } 161 157 } 162 158 163 159 ant_value_t blob_create(ant_t *js, const uint8_t *data, size_t size, const char *type) {
+5 -3
src/modules/builtin.c
··· 249 249 for (ant_object_t *obj = head; obj; obj = obj->next) { 250 250 obj_count++; 251 251 obj_bytes += sizeof(ant_object_t); 252 - 253 252 uint32_t inobj_limit = ant_object_inobj_limit(obj); 254 253 if (obj->overflow_prop && obj->prop_count > inobj_limit) 255 254 overflow_bytes += (obj->prop_count - inobj_limit) * sizeof(ant_value_t); 256 - if (obj->extra_slots) extra_bytes += obj->extra_count * sizeof(ant_extra_slot_t); 255 + uint8_t extra_count = 0; 256 + ant_extra_slot_t *slots = ant_object_extra_slots(obj, &extra_count); 257 + if (slots) extra_bytes += extra_count * sizeof(ant_extra_slot_t); 257 258 if (obj->promise_state) promise_bytes += sizeof(ant_promise_state_t); 258 - if (obj->proxy_state) proxy_bytes += sizeof(ant_proxy_state_t); 259 + if (ant_object_proxy_state(obj)) proxy_bytes += sizeof(ant_proxy_state_t); 260 + if (ant_object_has_sidecar(obj)) extra_bytes += sizeof(ant_object_sidecar_t); 259 261 if (obj->exotic_ops) exotic_bytes += sizeof(ant_exotic_ops_t); 260 262 if (obj->type_tag == T_ARR && obj->u.array.data) 261 263 array_bytes += obj->u.array.cap * sizeof(ant_value_t);
+8 -18
src/modules/formdata.c
··· 74 74 } 75 75 76 76 static void formdata_finalize(ant_t *js, ant_object_t *obj) { 77 - if (!obj->extra_slots) return; 78 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 79 - 80 - for (uint8_t i = 0; i < obj->extra_count; i++) { 81 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 82 - fd_data_t *d = (fd_data_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 83 - fd_data_free(d); 84 - return; 85 - }} 77 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 78 + if (!slot || vtype(slot->value) != T_NUM) return; 79 + fd_data_t *d = (fd_data_t *)(uintptr_t)(size_t)js_getnum(slot->value); 80 + fd_data_free(d); 86 81 } 87 82 88 83 static bool fd_append_str(fd_data_t *d, const char *name, const char *value) { ··· 412 407 } 413 408 414 409 static void formdata_iter_finalize(ant_t *js, ant_object_t *obj) { 415 - if (!obj->extra_slots) return; 416 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 417 - 418 - for (uint8_t i = 0; i < obj->extra_count; i++) { 419 - if (entries[i].slot == SLOT_ITER_STATE && vtype(entries[i].value) == T_NUM) { 420 - fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 421 - free(st); 422 - return; 423 - }} 410 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_ITER_STATE); 411 + if (!slot || vtype(slot->value) != T_NUM) return; 412 + fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(slot->value); 413 + free(st); 424 414 } 425 415 426 416 static ant_value_t make_formdata_iter(ant_t *js, ant_value_t fd_obj, int kind) {
+4 -8
src/modules/string_decoder.c
··· 37 37 } 38 38 39 39 static void sd_finalize(ant_t *js, ant_object_t *obj) { 40 - if (!obj->extra_slots) return; 41 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 42 - for (uint8_t i = 0; i < obj->extra_count; i++) { 43 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 44 - sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 45 - if (st) { free(st->td); free(st); } 46 - return; 47 - }} 40 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 41 + if (!slot || vtype(slot->value) != T_NUM) return; 42 + sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(slot->value); 43 + if (st) { free(st->td); free(st); } 48 44 } 49 45 50 46 static int sd_parse_encoding(const char *s, size_t len) {
+3 -8
src/modules/textcodec.c
··· 32 32 } 33 33 34 34 static void td_finalize(ant_t *js, ant_object_t *obj) { 35 - if (!obj->extra_slots) return; 36 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 37 - 38 - for (uint8_t i = 0; i < obj->extra_count; i++) { 39 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 40 - free((td_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 41 - return; 42 - }} 35 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 36 + if (!slot || vtype(slot->value) != T_NUM) return; 37 + free((td_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 43 38 } 44 39 45 40 static int resolve_encoding(const char *s, size_t len) {
+3 -7
src/modules/url.c
··· 49 49 } 50 50 51 51 static void url_finalize(ant_t *js, ant_object_t *obj) { 52 - if (!obj->extra_slots) return; 53 - ant_extra_slot_t *slots = (ant_extra_slot_t *)obj->extra_slots; 54 - for (uint8_t i = 0; i < obj->extra_count; i++) { 55 - if (slots[i].slot == SLOT_DATA && vtype(slots[i].value) == T_NUM) { 56 - url_free_state((url_state_t *)(uintptr_t)(size_t)js_getnum(slots[i].value)); 57 - return; 58 - }} 52 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 53 + if (!slot || vtype(slot->value) != T_NUM) return; 54 + url_free_state((url_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 59 55 } 60 56 61 57 static int default_port_for(const char *proto) {
+44 -50
src/modules/wasm.c
··· 373 373 } 374 374 375 375 static void wasm_module_finalize(ant_t *js, ant_object_t *obj) { 376 - if (!obj->extra_slots) return; 377 - 378 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 379 - for (uint8_t i = 0; i < obj->extra_count; i++) { 380 - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 381 - wasm_module_handle_t *handle = (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 382 - if (!handle) return; 383 - if (handle->module) wasm_module_delete(handle->module); 384 - if (handle->store) wasm_store_delete(handle->store); 385 - free(handle); 386 - return; 387 - } 376 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 377 + if (!slot || vtype(slot->value) != T_NUM) return; 378 + 379 + wasm_module_handle_t *handle = 380 + (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); 381 + 382 + if (!handle) return; 383 + if (handle->module) wasm_module_delete(handle->module); 384 + if (handle->store) wasm_store_delete(handle->store); 385 + 386 + free(handle); 388 387 } 389 388 390 389 static ant_value_t wasm_wrap_instance(ant_t *js, wasm_instance_handle_t *handle, ant_value_t module_ref) { ··· 397 396 } 398 397 399 398 static void wasm_instance_finalize(ant_t *js, ant_object_t *obj) { 400 - if (!obj->extra_slots) return; 401 - 402 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 403 - for (uint8_t i = 0; i < obj->extra_count; i++) { 404 - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 405 - wasm_instance_handle_t *handle = (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 406 - if (!handle) return; 407 - for (size_t j = 0; j < handle->host_func_count; j++) { 408 - if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); 409 - } 410 - free(handle->host_funcs); 411 - wasm_extern_vec_delete(&handle->exports); 412 - free(handle); 413 - return; 414 - } 399 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 400 + if (!slot || vtype(slot->value) != T_NUM) return; 401 + 402 + wasm_instance_handle_t *handle = 403 + (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); 404 + 405 + if (!handle) return; 406 + for (size_t j = 0; j < handle->host_func_count; j++) 407 + if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); 408 + 409 + free(handle->host_funcs); 410 + wasm_extern_vec_delete(&handle->exports); 411 + free(handle); 415 412 } 416 413 417 414 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 435 } 439 436 440 437 static void wasm_extern_finalize(ant_t *js, ant_object_t *obj) { 441 - if (!obj->extra_slots) return; 438 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 439 + if (!slot || vtype(slot->value) != T_NUM) return; 440 + 441 + wasm_extern_handle_t *handle = 442 + (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(slot->value); 443 + if (!handle) return; 442 444 443 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 444 - for (uint8_t i = 0; i < obj->extra_count; i++) { 445 - if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 446 - wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 447 - if (!handle) return; 448 - 449 - if (handle->own_handle) { 450 - switch (handle->kind) { 451 - case WASM_EXTERN_WRAP_GLOBAL: 452 - if (handle->as.global) wasm_global_delete(handle->as.global); 453 - break; 454 - case WASM_EXTERN_WRAP_MEMORY: 455 - if (handle->as.memory) wasm_memory_delete(handle->as.memory); 456 - break; 457 - case WASM_EXTERN_WRAP_TABLE: 458 - if (handle->as.table) wasm_table_delete(handle->as.table); 459 - break; 460 - } 461 - if (handle->store) wasm_store_delete(handle->store); 445 + if (handle->own_handle) { 446 + switch (handle->kind) { 447 + case WASM_EXTERN_WRAP_GLOBAL: 448 + if (handle->as.global) wasm_global_delete(handle->as.global); 449 + break; 450 + case WASM_EXTERN_WRAP_MEMORY: 451 + if (handle->as.memory) wasm_memory_delete(handle->as.memory); 452 + break; 453 + case WASM_EXTERN_WRAP_TABLE: 454 + if (handle->as.table) wasm_table_delete(handle->as.table); 455 + break; 462 456 } 457 + if (handle->store) wasm_store_delete(handle->store); 458 + } 463 459 464 - free(handle); 465 - return; 466 - } 460 + free(handle); 467 461 } 468 462 469 463 static ant_value_t js_wasm_exported_func_call(ant_t *js, ant_value_t *args, int nargs) {
+9 -1
src/silver/compiler.c
··· 8 8 #include "debug.h" 9 9 #include "tokens.h" 10 10 #include "runtime.h" 11 + #include "utils.h" 11 12 #include "ops/coercion.h" 12 13 13 14 #include <stdlib.h> ··· 345 346 } 346 347 347 348 sv_private_name_t *p = &scope->names[scope->count++]; 349 + 350 + uint64_t hash64 = hash_key(name->str, (size_t)name->len); 351 + uint32_t hash = (uint32_t)(hash64 ^ (hash64 >> 32)); 352 + 348 353 *p = (sv_private_name_t){ 349 354 .name = name->str, 350 355 .len = name->len, 351 356 .kind = kind, 357 + .hash = hash, 352 358 .is_static = is_static, 353 359 .has_getter = kind == SV_COMP_PRIVATE_GETTER, 354 360 .has_setter = kind == SV_COMP_PRIVATE_SETTER, 355 361 .owner = NULL, 356 362 .local = -1 357 363 }; 364 + 358 365 return true; 359 366 } 360 367 ··· 4655 4662 sv_private_name_t *p = &private_scope.names[i]; 4656 4663 p->owner = c; 4657 4664 p->local = add_local(c, "", 0, true, c->scope_depth); 4658 - emit_op(c, OP_OBJECT); 4665 + emit_op(c, OP_PRIVATE_TOKEN); 4666 + emit_u32(c, p->hash); 4659 4667 emit_put_local(c, p->local); 4660 4668 } 4661 4669 }
+3 -2
src/silver/engine.c
··· 965 965 L_ARRAY: { sv_op_array(vm, js, ip); NEXT(3); } 966 966 L_SET_BRAND: { sv_op_set_brand(vm, ip); NEXT(2); } 967 967 968 - L_REGEXP: { sv_op_regexp(vm, js); NEXT(1); } 969 - L_CLOSURE: { VM_CHECK(sv_op_closure(vm, js, frame, func, ip)); NEXT(5); } 968 + L_REGEXP: { sv_op_regexp(vm, js); NEXT(1); } 969 + L_CLOSURE: { VM_CHECK(sv_op_closure(vm, js, frame, func, ip)); NEXT(5); } 970 + L_PRIVATE_TOKEN: { sv_op_private_token(vm, js, ip); NEXT(5); } 970 971 971 972 L_POP: { sv_op_pop(vm); NEXT(1); } 972 973 L_DUP: { sv_op_dup(vm); NEXT(1); }
+7
src/silver/ops/literals.h
··· 75 75 vm->stack[vm->sp++] = obj; 76 76 } 77 77 78 + static inline void sv_op_private_token(sv_vm_t *vm, ant_t *js, uint8_t *ip) { 79 + ant_value_t obj = mkobj(js, 0); 80 + uint32_t hash = sv_get_u32(ip + 1); 81 + js_set_slot(obj, SLOT_DATA, js_mknum((double)hash)); 82 + vm->stack[vm->sp++] = obj; 83 + } 84 + 78 85 static inline void sv_op_array(sv_vm_t *vm, ant_t *js, uint8_t *ip) { 79 86 uint16_t n = sv_get_u16(ip + 1); 80 87 ant_value_t arr = js_mkarr(js);
+164 -86
src/silver/ops/private.h
··· 1 1 #ifndef SV_PRIVATE_H 2 2 #define SV_PRIVATE_H 3 3 4 + #include <stdlib.h> 5 + #include "gc.h" 6 + #include "object.h" 4 7 #include "silver/engine.h" 5 - #include <stdio.h> 6 8 7 9 enum { 8 10 SV_PRIVATE_FIELD = 0, ··· 12 14 SV_PRIVATE_SETTER = 4 13 15 }; 14 16 15 - static inline ant_value_t sv_private_entry_get(ant_t *js, ant_value_t entry, ant_offset_t idx) { 16 - return vtype(entry) == T_ARR 17 - ? js_arr_get(js, entry, idx) 18 - : js_mkundef(); 17 + static inline uint32_t sv_private_hash_token(ant_value_t token) { 18 + if (is_object_type(token)) { 19 + ant_value_t cached = js_get_slot(token, SLOT_DATA); 20 + if (vtype(cached) == T_NUM) return (uint32_t)js_getnum(cached); 21 + } 22 + 23 + uint64_t x = token ^ (token >> 33); 24 + x *= 0xff51afd7ed558ccdULL; 25 + x ^= x >> 33; 26 + x *= 0xc4ceb9fe1a85ec53ULL; 27 + x ^= x >> 33; 28 + 29 + return (uint32_t)x; 19 30 } 20 31 21 - static inline ant_value_t sv_private_entry_set(ant_t *js, ant_value_t entry, ant_offset_t idx, ant_value_t value) { 22 - char key_buf[8]; 23 - int key_len = snprintf(key_buf, sizeof(key_buf), "%u", (unsigned)idx); 24 - return js_setprop(js, entry, js_mkstr(js, key_buf, (size_t)key_len), value); 32 + static inline ant_private_table_t *sv_private_table_for_obj(ant_value_t obj, bool create) { 33 + if (!is_object_type(obj)) return NULL; 34 + ant_object_t *ptr = js_obj_ptr(js_as_obj(obj)); 35 + if (!ptr) return NULL; 36 + ant_object_sidecar_t *sidecar = create ? ant_object_ensure_sidecar(ptr) : ant_object_sidecar(ptr); 37 + return sidecar ? &sidecar->private_table : NULL; 25 38 } 26 39 27 - static inline ant_value_t sv_private_table(ant_t *js, ant_value_t obj, bool create) { 28 - if (!is_object_type(obj)) return js_mkundef(); 29 - ant_value_t table = js_get_slot(obj, SLOT_PRIVATE_ELEMENTS); 40 + static inline uint32_t sv_private_find_slot( 41 + ant_private_table_t *table, ant_value_t token, uint32_t hash, bool *found 42 + ) { 43 + uint32_t mask = table->cap - 1; 44 + uint32_t idx = hash & mask; 30 45 31 - if (vtype(table) == T_ARR) return table; 32 - if (!create) return js_mkundef(); 33 - table = js_mkarr(js); 46 + for (;;) { 47 + ant_private_entry_t *entry = &table->entries[idx]; 48 + if (!entry->occupied) { 49 + *found = false; 50 + return idx; 51 + } 52 + 53 + if (entry->hash == hash && entry->token == token) { 54 + *found = true; 55 + return idx; 56 + } 57 + 58 + idx = (idx + 1) & mask; 59 + } 60 + } 61 + 62 + static inline bool sv_private_table_grow(ant_private_table_t *table) { 63 + uint32_t old_cap = table->cap; 64 + uint32_t new_cap = old_cap ? old_cap * 2 : 8; 34 65 35 - if (is_err(table)) return table; 36 - js_set_slot_wb(js, obj, SLOT_PRIVATE_ELEMENTS, table); 37 - 38 - return table; 39 - } 66 + ant_private_entry_t *new_entries = 67 + (ant_private_entry_t *)calloc(new_cap, sizeof(*new_entries)); 68 + if (!new_entries) return false; 40 69 41 - static inline ant_value_t sv_private_cached_entry( 42 - ant_t *js, ant_value_t table, ant_value_t token, ant_offset_t len 43 - ) { 44 - if (!is_object_type(token)) return js_mkundef(); 45 - ant_value_t cached = js_get_slot(token, SLOT_DATA); 46 - if (vtype(cached) != T_NUM) return js_mkundef(); 70 + ant_private_entry_t *old_entries = table->entries; 71 + table->entries = new_entries; 72 + table->cap = new_cap; 73 + table->count = 0; 47 74 48 - double idx_num = js_getnum(cached); 49 - if (idx_num < 0 || idx_num >= (double)len) return js_mkundef(); 75 + for (uint32_t i = 0; i < old_cap; i++) { 76 + ant_private_entry_t entry = old_entries[i]; 77 + if (!entry.occupied) continue; 78 + 79 + bool found = false; 80 + uint32_t slot = sv_private_find_slot( 81 + table, entry.token, 82 + entry.hash, &found 83 + ); 84 + 85 + table->entries[slot] = entry; 86 + table->count++; 87 + } 50 88 51 - ant_offset_t idx = (ant_offset_t)idx_num; 52 - ant_value_t entry = js_arr_get(js, table, idx); 53 - if (vtype(entry) == T_ARR && sv_private_entry_get(js, entry, 0) == token) 54 - return entry; 55 - return js_mkundef(); 89 + free(old_entries); 90 + return true; 56 91 } 57 92 58 - static inline void sv_private_cache_entry(ant_t *js, ant_value_t token, ant_offset_t idx) { 59 - if (is_object_type(token)) 60 - js_set_slot(token, SLOT_DATA, js_mknum((double)idx)); 93 + static inline ant_private_entry_t *sv_private_find_entry(ant_value_t obj, ant_value_t token) { 94 + ant_private_table_t *table = sv_private_table_for_obj(obj, false); 95 + if (!table || !table->entries || table->cap == 0) return NULL; 96 + 97 + bool found = false; 98 + uint32_t hash = sv_private_hash_token(token); 99 + uint32_t slot = sv_private_find_slot(table, token, hash, &found); 100 + 101 + return found ? &table->entries[slot] : NULL; 61 102 } 62 103 63 - static inline ant_value_t sv_private_find_entry(ant_t *js, ant_value_t obj, ant_value_t token) { 64 - ant_value_t table = sv_private_table(js, obj, false); 65 - if (vtype(table) != T_ARR) return js_mkundef(); 66 - ant_offset_t len = js_arr_len(js, table); 104 + static inline ant_value_t sv_private_entry_get(ant_private_entry_t *entry, ant_offset_t idx) { 105 + if (!entry) return js_mkundef(); 106 + 107 + switch (idx) { 108 + case 0: return entry->token; 109 + case 1: return js_mknum((double)entry->kind); 110 + case 2: return entry->value; 111 + case 3: return entry->getter; 112 + case 4: return entry->setter; 113 + default: return js_mkundef(); 114 + } 115 + } 67 116 68 - ant_value_t cached = sv_private_cached_entry(js, table, token, len); 69 - if (vtype(cached) != T_UNDEF) return cached; 117 + static inline ant_value_t sv_private_entry_set( 118 + ant_t *js, ant_value_t obj, ant_private_entry_t *entry, ant_offset_t idx, ant_value_t value 119 + ) { 120 + if (!entry) return js_mkundef(); 121 + 122 + switch (idx) { 123 + case 2: entry->value = value; break; 124 + case 3: entry->getter = value; break; 125 + case 4: entry->setter = value; break; 126 + default: return js_mkundef(); 127 + } 70 128 71 - for (ant_offset_t i = 0; i < len; i++) { 72 - ant_value_t entry = js_arr_get(js, table, i); 73 - if (vtype(entry) == T_ARR && sv_private_entry_get(js, entry, 0) == token) { 74 - sv_private_cache_entry(js, token, i); 75 - return entry; 76 - }} 129 + ant_object_t *ptr = is_object_type(obj) ? js_obj_ptr(js_as_obj(obj)) : NULL; 130 + if (ptr) gc_write_barrier(js, ptr, value); 77 131 78 132 return js_mkundef(); 79 133 } 80 134 81 - static inline ant_value_t sv_private_make_entry( 135 + static inline ant_private_entry_t *sv_private_make_entry( 82 136 ant_t *js, ant_value_t obj, ant_value_t token, 83 137 int kind, ant_value_t value, ant_value_t getter, ant_value_t setter 84 138 ) { 85 - ant_value_t table = sv_private_table(js, obj, true); 86 - if (is_err(table)) return table; 139 + ant_private_table_t *table = sv_private_table_for_obj(obj, true); 140 + if (!table) return NULL; 87 141 88 - ant_value_t entry = js_mkarr(js); 89 - if (is_err(entry)) return entry; 90 - js_arr_push(js, entry, token); 91 - js_arr_push(js, entry, js_mknum((double)kind)); 92 - js_arr_push(js, entry, value); 93 - js_arr_push(js, entry, getter); 94 - js_arr_push(js, entry, setter); 142 + if (table->cap == 0 || ((table->count + 1) * 4 >= table->cap * 3)) { 143 + if (!sv_private_table_grow(table)) return NULL; 144 + } 145 + 146 + bool found = false; 147 + uint32_t hash = sv_private_hash_token(token); 148 + uint32_t slot = sv_private_find_slot(table, token, hash, &found); 149 + ant_private_entry_t *entry = &table->entries[slot]; 95 150 96 - ant_offset_t idx = js_arr_len(js, table); 97 - js_arr_push(js, table, entry); 98 - sv_private_cache_entry(js, token, idx); 99 - 151 + if (!found) { 152 + *entry = (ant_private_entry_t){ 153 + .token = token, 154 + .value = value, 155 + .getter = getter, 156 + .setter = setter, 157 + .hash = hash, 158 + .kind = (uint8_t)kind, 159 + .occupied = 1 160 + }; 161 + table->count++; 162 + } 163 + 164 + ant_object_t *ptr = js_obj_ptr(js_as_obj(obj)); 165 + if (ptr) { 166 + gc_write_barrier(js, ptr, token); 167 + gc_write_barrier(js, ptr, value); 168 + gc_write_barrier(js, ptr, getter); 169 + gc_write_barrier(js, ptr, setter); 170 + } 171 + 100 172 return entry; 101 173 } 102 174 ··· 116 188 return sv_private_missing(js); 117 189 } 118 190 119 - ant_value_t entry = sv_private_find_entry(js, obj, token); 120 - if (vtype(entry) == T_UNDEF) return sv_private_missing(js); 191 + ant_private_entry_t *entry = sv_private_find_entry(obj, token); 192 + if (!entry) return sv_private_missing(js); 121 193 122 - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); 123 - int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; 194 + ant_value_t kind_val = sv_private_entry_get(entry, 1); 195 + int kind = vtype(kind_val) == T_NUM 196 + ? (int)js_getnum(kind_val) 197 + : SV_PRIVATE_FIELD; 198 + 124 199 if (kind == SV_PRIVATE_ACCESSOR) { 125 - ant_value_t getter = sv_private_entry_get(js, entry, 3); 200 + ant_value_t getter = sv_private_entry_get(entry, 3); 126 201 if (vtype(getter) == T_UNDEF) 127 202 return js_mkerr_typed(js, JS_ERR_TYPE, "Private accessor has no getter"); 128 203 ant_value_t result = sv_vm_call_explicit_this(vm, js, getter, obj, NULL, 0); ··· 131 206 return js_mkundef(); 132 207 } 133 208 134 - vm->stack[vm->sp++] = sv_private_entry_get(js, entry, 2); 209 + vm->stack[vm->sp++] = sv_private_entry_get(entry, 2); 135 210 return js_mkundef(); 136 211 } 137 212 ··· 149 224 ant_value_t obj = vm->stack[--vm->sp]; 150 225 151 226 if (!is_object_type(obj)) return sv_private_missing(js); 152 - ant_value_t entry = sv_private_find_entry(js, obj, token); 153 - if (vtype(entry) == T_UNDEF) return sv_private_missing(js); 227 + ant_private_entry_t *entry = sv_private_find_entry(obj, token); 228 + if (!entry) return sv_private_missing(js); 154 229 155 - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); 230 + ant_value_t kind_val = sv_private_entry_get(entry, 1); 156 231 int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; 157 232 if (kind == SV_PRIVATE_FIELD) { 158 - ant_value_t set = sv_private_entry_set(js, entry, 2, val); 233 + ant_value_t set = sv_private_entry_set(js, obj, entry, 2, val); 159 234 if (is_err(set)) return set; 160 235 vm->stack[vm->sp++] = val; 161 236 return js_mkundef(); 162 237 } 163 238 164 239 if (kind == SV_PRIVATE_ACCESSOR) { 165 - ant_value_t setter = sv_private_entry_get(js, entry, 4); 240 + ant_value_t setter = sv_private_entry_get(entry, 4); 166 241 if (vtype(setter) == T_UNDEF) 167 242 return js_mkerr_typed(js, JS_ERR_TYPE, "Private accessor has no setter"); 168 243 ant_value_t args[1] = { val }; ··· 182 257 ant_value_t obj = vm->stack[vm->sp - 1]; 183 258 184 259 if (!is_object_type(obj)) return sv_private_missing(js); 185 - ant_value_t existing = sv_private_find_entry(js, obj, token); 260 + ant_private_entry_t *existing = sv_private_find_entry(obj, token); 186 261 187 262 if (def_kind == SV_PRIVATE_GETTER || def_kind == SV_PRIVATE_SETTER) { 188 - ant_value_t entry = existing; 189 - if (vtype(entry) == T_UNDEF) { 263 + ant_private_entry_t *entry = existing; 264 + if (!entry) { 190 265 entry = sv_private_make_entry( 191 266 js, obj, token, SV_PRIVATE_ACCESSOR, 192 267 js_mkundef(), 193 268 def_kind == SV_PRIVATE_GETTER ? val : js_mkundef(), 194 269 def_kind == SV_PRIVATE_SETTER ? val : js_mkundef()); 195 - return is_err(entry) ? entry : js_mkundef(); 270 + return entry ? js_mkundef() : js_mkerr(js, "oom"); 196 271 } 197 - 198 - ant_value_t kind_val = sv_private_entry_get(js, entry, 1); 272 + 273 + ant_value_t kind_val = sv_private_entry_get(entry, 1); 199 274 int kind = vtype(kind_val) == T_NUM ? (int)js_getnum(kind_val) : SV_PRIVATE_FIELD; 200 275 if (kind != SV_PRIVATE_ACCESSOR) 201 276 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot redefine private member"); 202 - 277 + 203 278 ant_offset_t slot = def_kind == SV_PRIVATE_GETTER ? 3 : 4; 204 - if (vtype(sv_private_entry_get(js, entry, slot)) != T_UNDEF) 279 + if (vtype(sv_private_entry_get(entry, slot)) != T_UNDEF) 205 280 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot redefine private accessor"); 206 - return sv_private_entry_set(js, entry, slot, val); 281 + return sv_private_entry_set(js, obj, entry, slot, val); 207 282 } 208 283 209 - if (vtype(existing) != T_UNDEF) 284 + if (existing) 210 285 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot initialize private member twice"); 211 286 212 - ant_value_t entry = sv_private_make_entry( 287 + ant_private_entry_t *entry = sv_private_make_entry( 213 288 js, obj, token, 214 289 def_kind == SV_PRIVATE_METHOD ? SV_PRIVATE_METHOD : SV_PRIVATE_FIELD, 215 290 val, js_mkundef(), js_mkundef()); 216 - return is_err(entry) ? entry : js_mkundef(); 291 + 292 + return entry ? js_mkundef() : js_mkerr(js, "oom"); 217 293 } 218 294 219 295 static inline ant_value_t sv_op_has_private(sv_vm_t *vm, ant_t *js) { 220 296 ant_value_t token = vm->stack[--vm->sp]; 221 297 ant_value_t obj = vm->stack[--vm->sp]; 298 + 222 299 if (!is_object_type(obj)) 223 300 return js_mkerr_typed(js, JS_ERR_TYPE, "Right operand of private brand check must be an object"); 224 - vm->stack[vm->sp++] = js_bool(vtype(sv_private_find_entry(js, obj, token)) != T_UNDEF); 301 + vm->stack[vm->sp++] = js_bool(sv_private_find_entry(obj, token) != NULL); 302 + 225 303 return js_mkundef(); 226 304 } 227 305
+6 -14
src/streams/codec.c
··· 58 58 } 59 59 60 60 static void tes_state_finalize(ant_t *js, ant_object_t *obj) { 61 - if (!obj->extra_slots) return; 62 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 63 - for (uint8_t i = 0; i < obj->extra_count; i++) { 64 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 65 - free((tes_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 66 - return; 67 - }} 61 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 62 + if (!slot || vtype(slot->value) != T_NUM) return; 63 + free((tes_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 68 64 } 69 65 70 66 static void tds_state_finalize(ant_t *js, ant_object_t *obj) { 71 - if (!obj->extra_slots) return; 72 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 73 - for (uint8_t i = 0; i < obj->extra_count; i++) { 74 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 75 - free((td_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 76 - return; 77 - }} 67 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 68 + if (!slot || vtype(slot->value) != T_NUM) return; 69 + free((td_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 78 70 } 79 71 80 72 static ant_value_t codec_transform_controller(ant_value_t *args, int nargs) {
+15 -28
src/streams/compression.c
··· 83 83 } 84 84 85 85 static void zstate_finalize(ant_t *js, ant_object_t *obj) { 86 - if (!obj->extra_slots) return; 87 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 88 - for (uint8_t i = 0; i < obj->extra_count; i++) { 89 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 90 - zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 91 - if (st->initialized) deflateEnd(&st->strm); 92 - free(st); 93 - return; 94 - }} 86 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 87 + if (!slot || vtype(slot->value) != T_NUM) return; 88 + zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(slot->value); 89 + if (st->initialized) deflateEnd(&st->strm); 90 + free(st); 95 91 } 96 92 97 93 static void zstate_inflate_finalize(ant_t *js, ant_object_t *obj) { 98 - if (!obj->extra_slots) return; 99 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 100 - for (uint8_t i = 0; i < obj->extra_count; i++) { 101 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 102 - zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 103 - if (st->initialized) inflateEnd(&st->strm); 104 - free(st); 105 - return; 106 - }} 94 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 95 + if (!slot || vtype(slot->value) != T_NUM) return; 96 + zstate_t *st = (zstate_t *)(uintptr_t)(size_t)js_getnum(slot->value); 97 + if (st->initialized) inflateEnd(&st->strm); 98 + free(st); 107 99 } 108 100 109 101 static void brotli_state_finalize(ant_t *js, ant_object_t *obj) { 110 - if (!obj->extra_slots) return; 111 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 112 - 113 - for (uint8_t i = 0; i < obj->extra_count; i++) { 114 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 115 - brotli_stream_state_t *st = 116 - (brotli_stream_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 117 - brotli_stream_state_destroy(st); 118 - return; 119 - }} 102 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 103 + if (!slot || vtype(slot->value) != T_NUM) return; 104 + brotli_stream_state_t *st = 105 + (brotli_stream_state_t *)(uintptr_t)(size_t)js_getnum(slot->value); 106 + brotli_stream_state_destroy(st); 120 107 } 121 108 122 109 static ant_value_t enqueue_buffer(ant_t *js, ant_value_t ctrl_obj, const uint8_t *data, size_t len) {
+6 -14
src/streams/pipes.c
··· 46 46 } 47 47 48 48 static void pipe_state_finalize(ant_t *js, ant_object_t *obj) { 49 - if (!obj->extra_slots) return; 50 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 51 - for (uint8_t i = 0; i < obj->extra_count; i++) { 52 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 53 - free((pipe_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 54 - return; 55 - }} 49 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 50 + if (!slot || vtype(slot->value) != T_NUM) return; 51 + free((pipe_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 56 52 } 57 53 58 54 static pipe_state_t *pipe_get_state(ant_value_t state) { ··· 487 483 } tee_state_t; 488 484 489 485 static void tee_state_finalize(ant_t *js, ant_object_t *obj) { 490 - if (!obj->extra_slots) return; 491 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 492 - for (uint8_t i = 0; i < obj->extra_count; i++) { 493 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 494 - free((tee_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 495 - return; 496 - }} 486 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 487 + if (!slot || vtype(slot->value) != T_NUM) return; 488 + free((tee_state_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 497 489 } 498 490 499 491 static tee_state_t *tee_get_state(ant_value_t state) {
+9 -16
src/streams/readable.c
··· 61 61 } 62 62 63 63 static void rs_stream_finalize(ant_t *js, ant_object_t *obj) { 64 - if (!obj->extra_slots) return; 65 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 66 - for (uint8_t i = 0; i < obj->extra_count; i++) { 67 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 68 - free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 69 - return; 70 - }} 64 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 65 + if (!slot || vtype(slot->value) != T_NUM) return; 66 + free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 71 67 } 72 68 73 69 static void rs_controller_finalize(ant_t *js, ant_object_t *obj) { 74 - if (!obj->extra_slots) return; 75 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 76 - for (uint8_t i = 0; i < obj->extra_count; i++) { 77 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 78 - rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 79 - free(ctrl->queue_sizes); 80 - free(ctrl); 81 - return; 82 - }} 70 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 71 + if (!slot || vtype(slot->value) != T_NUM) return; 72 + rs_controller_t *ctrl = 73 + (rs_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); 74 + free(ctrl->queue_sizes); 75 + free(ctrl); 83 76 } 84 77 85 78 ant_value_t rs_stream_controller(ant_t *js, ant_value_t stream_obj) {
+18 -32
src/streams/transform.c
··· 54 54 } 55 55 56 56 static void ts_ws_finalize(ant_t *js, ant_object_t *obj) { 57 - if (!obj->extra_slots) return; 58 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 59 - for (uint8_t i = 0; i < obj->extra_count; i++) { 60 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 61 - free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 62 - return; 63 - }} 57 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 58 + if (!slot || vtype(slot->value) != T_NUM) return; 59 + free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 64 60 } 65 61 66 62 static void ts_ws_ctrl_finalize(ant_t *js, ant_object_t *obj) { 67 - if (!obj->extra_slots) return; 68 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 69 - for (uint8_t i = 0; i < obj->extra_count; i++) { 70 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 71 - ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 72 - free(ctrl->queue_sizes); 73 - free(ctrl); 74 - return; 75 - }} 63 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 64 + if (!slot || vtype(slot->value) != T_NUM) return; 65 + ws_controller_t *ctrl = 66 + (ws_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); 67 + free(ctrl->queue_sizes); 68 + free(ctrl); 76 69 } 77 70 78 71 static void ts_rs_finalize(ant_t *js, ant_object_t *obj) { 79 - if (!obj->extra_slots) return; 80 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 81 - for (uint8_t i = 0; i < obj->extra_count; i++) { 82 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 83 - free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 84 - return; 85 - }} 72 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 73 + if (!slot || vtype(slot->value) != T_NUM) return; 74 + free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 86 75 } 87 76 88 77 static void ts_rs_ctrl_finalize(ant_t *js, ant_object_t *obj) { 89 - if (!obj->extra_slots) return; 90 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 91 - for (uint8_t i = 0; i < obj->extra_count; i++) { 92 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 93 - rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 94 - free(ctrl->queue_sizes); 95 - free(ctrl); 96 - return; 97 - }} 78 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 79 + if (!slot || vtype(slot->value) != T_NUM) return; 80 + rs_controller_t *ctrl = 81 + (rs_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); 82 + free(ctrl->queue_sizes); 83 + free(ctrl); 98 84 } 99 85 100 86 static inline bool ts_get_backpressure(ant_value_t ts_obj) {
+9 -16
src/streams/writable.c
··· 49 49 } 50 50 51 51 static void ws_stream_finalize(ant_t *js, ant_object_t *obj) { 52 - if (!obj->extra_slots) return; 53 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 54 - for (uint8_t i = 0; i < obj->extra_count; i++) { 55 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 56 - free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 57 - return; 58 - }} 52 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 53 + if (!slot || vtype(slot->value) != T_NUM) return; 54 + free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(slot->value)); 59 55 } 60 56 61 57 static void ws_controller_finalize(ant_t *js, ant_object_t *obj) { 62 - if (!obj->extra_slots) return; 63 - ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 64 - for (uint8_t i = 0; i < obj->extra_count; i++) { 65 - if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 66 - ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 67 - free(ctrl->queue_sizes); 68 - free(ctrl); 69 - return; 70 - }} 58 + ant_extra_slot_t *slot = ant_object_extra_slot(obj, SLOT_DATA); 59 + if (!slot || vtype(slot->value) != T_NUM) return; 60 + ws_controller_t *ctrl = 61 + (ws_controller_t *)(uintptr_t)(size_t)js_getnum(slot->value); 62 + free(ctrl->queue_sizes); 63 + free(ctrl); 71 64 } 72 65 73 66 ant_value_t ws_stream_controller(ant_value_t stream_obj) {