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.

at mir/inline-method 1677 lines 58 kB view raw
1#include <stdlib.h> 2#include <string.h> 3#include <stdio.h> 4#include <math.h> 5 6#include "ant.h" 7#include "gc.h" 8#include "errors.h" 9#include "runtime.h" 10#include "internal.h" 11#include "silver/engine.h" 12#include "descriptors.h" 13 14#include "modules/bigint.h" 15#include "modules/collections.h" 16#include "modules/symbol.h" 17 18ant_value_t g_map_iter_proto = 0; 19ant_value_t g_set_iter_proto = 0; 20 21typedef struct { 22 unsigned char stack[32]; 23 unsigned char *bytes; 24 size_t len; 25} collection_key_t; 26 27static ant_value_t normalize_map_key(ant_value_t key) { 28 if (vtype(key) == T_NUM) { 29 double d = tod(key); 30 if (d == 0.0 && signbit(d)) return js_mknum(0.0); 31 } 32 return key; 33} 34 35static void collection_key_reset(collection_key_t *key) { 36 key->bytes = key->stack; 37 key->len = 0; 38} 39 40static void collection_key_free(collection_key_t *key) { 41 if (key->bytes != key->stack) free(key->bytes); 42 collection_key_reset(key); 43} 44 45static bool collection_key_reserve(collection_key_t *key, size_t len) { 46 if (len <= sizeof(key->stack)) return true; 47 unsigned char *heap = malloc(len); 48 if (!heap) return false; 49 key->bytes = heap; 50 return true; 51} 52 53static bool collection_key_init(ant_t *js, ant_value_t input, collection_key_t *out) { 54 collection_key_reset(out); 55 56 ant_value_t key = normalize_map_key(input); 57 uint8_t tag = (uint8_t)vtype(key); 58 59 if (vtype(key) == T_STR) { 60 size_t str_len = 0; 61 const char *str = js_getstr(js, key, &str_len); 62 out->len = 1 + str_len; 63 if (!collection_key_reserve(out, out->len)) return false; 64 out->bytes[0] = tag; 65 if (str_len > 0) memcpy(out->bytes + 1, str, str_len); 66 return true; 67 } 68 69 if (vtype(key) == T_BIGINT) { 70 size_t str_len = bigint_digits_len(js, key) + (bigint_is_negative(js, key) ? 1 : 0); 71 out->len = 1 + str_len; 72 if (!collection_key_reserve(out, out->len)) return false; 73 out->bytes[0] = tag; 74 if (str_len > 0) strbigint(js, key, (char *)(out->bytes + 1), str_len + 1); 75 return true; 76 } 77 78 out->len = 1 + sizeof(ant_value_t); 79 if (!collection_key_reserve(out, out->len)) return false; 80 out->bytes[0] = tag; 81 memcpy(out->bytes + 1, &key, sizeof(ant_value_t)); 82 83 return true; 84} 85 86static map_entry_t *map_find_entry(ant_t *js, map_entry_t **map_ptr, ant_value_t key_val) { 87 collection_key_t key; 88 if (!collection_key_init(js, key_val, &key)) return NULL; 89 90 map_entry_t *entry = NULL; 91 HASH_FIND(hh, *map_ptr, key.bytes, key.len, entry); 92 collection_key_free(&key); 93 94 return entry; 95} 96 97static set_entry_t *set_find_entry(ant_t *js, set_entry_t **set_ptr, ant_value_t value) { 98 collection_key_t key; 99 if (!collection_key_init(js, value, &key)) return NULL; 100 101 set_entry_t *entry = NULL; 102 HASH_FIND(hh, *set_ptr, key.bytes, key.len, entry); 103 collection_key_free(&key); 104 105 return entry; 106} 107 108static bool map_store_entry( 109 ant_t *js, 110 map_entry_t **map_ptr, 111 ant_value_t raw_key, 112 ant_value_t key_val, 113 ant_value_t value 114) { 115 collection_key_t key; 116 if (!collection_key_init(js, raw_key, &key)) return false; 117 118 map_entry_t *entry = NULL; 119 HASH_FIND(hh, *map_ptr, key.bytes, key.len, entry); 120 if (entry) { 121 entry->key_val = key_val; 122 entry->value = value; 123 collection_key_free(&key); 124 return true; 125 } 126 127 entry = ant_calloc(sizeof(map_entry_t)); 128 if (!entry) { 129 collection_key_free(&key); 130 return false; 131 } 132 133 entry->key = malloc(key.len); 134 if (!entry->key) { 135 collection_key_free(&key); 136 free(entry); 137 return false; 138 } 139 140 memcpy(entry->key, key.bytes, key.len); 141 entry->key_len = key.len; 142 entry->key_val = key_val; 143 entry->value = value; 144 145 HASH_ADD_KEYPTR(hh, *map_ptr, entry->key, entry->key_len, entry); 146 collection_key_free(&key); 147 148 return true; 149} 150 151static bool set_store_entry(ant_t *js, set_entry_t **set_ptr, ant_value_t value) { 152 collection_key_t key; 153 if (!collection_key_init(js, value, &key)) return false; 154 155 set_entry_t *entry = NULL; 156 HASH_FIND(hh, *set_ptr, key.bytes, key.len, entry); 157 if (entry) { 158 collection_key_free(&key); 159 return true; 160 } 161 162 entry = ant_calloc(sizeof(set_entry_t)); 163 if (!entry) { 164 collection_key_free(&key); 165 return false; 166 } 167 168 entry->key = malloc(key.len); 169 if (!entry->key) { 170 collection_key_free(&key); 171 free(entry); 172 return false; 173 } 174 175 memcpy(entry->key, key.bytes, key.len); 176 entry->key_len = key.len; 177 entry->value = value; 178 179 HASH_ADD_KEYPTR(hh, *set_ptr, entry->key, entry->key_len, entry); 180 collection_key_free(&key); 181 182 return true; 183} 184 185static ant_value_t map_init_from_iterable(ant_t *js, map_entry_t **map_head, ant_value_t iterable) { 186 js_iter_t it; 187 if (!js_iter_open(js, iterable, &it)) { 188 return js_mkerr_typed(js, JS_ERR_TYPE, "Map constructor argument is not iterable"); 189 } 190 191 ant_value_t entry; 192 while (js_iter_next(js, &it, &entry)) { 193 uint8_t entry_t = vtype(entry); 194 if (entry_t != T_ARR && entry_t != T_OBJ) { 195 js_iter_close(js, &it); 196 return js_mkerr_typed(js, JS_ERR_TYPE, "Map iterable entries must be pair sequences"); 197 } 198 199 ant_offset_t entry_len = js_arr_len(js, entry); 200 if (entry_len < 2) { 201 js_iter_close(js, &it); 202 return js_mkerr_typed(js, JS_ERR_TYPE, "Map iterable entries must have at least 2 items"); 203 } 204 205 ant_value_t key = normalize_map_key(js_arr_get(js, entry, 0)); 206 ant_value_t value = js_arr_get(js, entry, 1); 207 if (!map_store_entry(js, map_head, key, key, value)) { 208 js_iter_close(js, &it); 209 return js_mkerr(js, "out of memory"); 210 }} 211 212 return js_mkundef(); 213} 214 215static ant_value_t set_init_from_iterable(ant_t *js, set_entry_t **set_head, ant_value_t iterable) { 216 js_iter_t it; 217 if (!js_iter_open(js, iterable, &it)) { 218 return js_mkerr_typed(js, JS_ERR_TYPE, "Set constructor argument is not iterable"); 219 } 220 221 ant_value_t value; 222 while (js_iter_next(js, &it, &value)) if (!set_store_entry(js, set_head, value)) { 223 js_iter_close(js, &it); 224 return js_mkerr(js, "out of memory"); 225 } 226 227 return js_mkundef(); 228} 229 230static ant_value_t weakmap_init_from_iterable(ant_t *js, weakmap_entry_t **wm_head, ant_value_t iterable) { 231 js_iter_t it; 232 if (!js_iter_open(js, iterable, &it)) { 233 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap constructor argument is not iterable"); 234 } 235 236 ant_value_t entry; 237 while (js_iter_next(js, &it, &entry)) { 238 uint8_t entry_t = vtype(entry); 239 if (entry_t != T_ARR && entry_t != T_OBJ) { 240 js_iter_close(js, &it); 241 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap iterable entries must be pair sequences"); 242 } 243 244 ant_offset_t entry_len = js_arr_len(js, entry); 245 if (entry_len < 2) { 246 js_iter_close(js, &it); 247 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap iterable entries must have at least 2 items"); 248 } 249 250 ant_value_t key = js_arr_get(js, entry, 0); 251 ant_value_t value = js_arr_get(js, entry, 1); 252 if (!is_object_type(key)) { 253 js_iter_close(js, &it); 254 return js_mkerr(js, "WeakMap key must be an object"); 255 } 256 257 weakmap_entry_t *wm_entry; 258 HASH_FIND(hh, *wm_head, &key, sizeof(ant_value_t), wm_entry); 259 if (wm_entry) { 260 wm_entry->value = value; 261 continue; 262 } 263 264 wm_entry = ant_calloc(sizeof(weakmap_entry_t)); 265 if (!wm_entry) { 266 js_iter_close(js, &it); 267 return js_mkerr(js, "out of memory"); 268 } 269 270 wm_entry->key_obj = key; 271 wm_entry->value = value; 272 HASH_ADD(hh, *wm_head, key_obj, sizeof(ant_value_t), wm_entry); 273 } 274 275 return js_mkundef(); 276} 277 278static ant_value_t weakset_init_from_iterable(ant_t *js, weakset_entry_t **ws_head, ant_value_t iterable) { 279 js_iter_t it; 280 if (!js_iter_open(js, iterable, &it)) { 281 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakSet constructor argument is not iterable"); 282 } 283 284 ant_value_t value; 285 while (js_iter_next(js, &it, &value)) { 286 if (!is_object_type(value)) { 287 js_iter_close(js, &it); 288 return js_mkerr(js, "WeakSet value must be an object"); 289 } 290 291 weakset_entry_t *entry; 292 HASH_FIND(hh, *ws_head, &value, sizeof(ant_value_t), entry); 293 if (entry) continue; 294 295 entry = ant_calloc(sizeof(weakset_entry_t)); 296 if (!entry) { 297 js_iter_close(js, &it); 298 return js_mkerr(js, "out of memory"); 299 } 300 301 entry->value_obj = value; 302 HASH_ADD(hh, *ws_head, value_obj, sizeof(ant_value_t), entry); 303 } 304 305 return js_mkundef(); 306} 307 308map_entry_t **get_map_from_obj(ant_value_t obj) { 309 ant_object_t *ptr = js_obj_ptr(obj); 310 if (!ptr || ptr->type_tag != T_MAP) return NULL; 311 return (map_entry_t **)(uintptr_t)js_getnum(ptr->u.data.value); 312} 313 314set_entry_t **get_set_from_obj(ant_value_t obj) { 315 ant_object_t *ptr = js_obj_ptr(obj); 316 if (!ptr || ptr->type_tag != T_SET) return NULL; 317 return (set_entry_t **)(uintptr_t)js_getnum(ptr->u.data.value); 318} 319 320static weakmap_entry_t **get_weakmap_from_obj(ant_value_t obj) { 321 ant_object_t *ptr = js_obj_ptr(obj); 322 if (!ptr || ptr->type_tag != T_WEAKMAP) return NULL; 323 return (weakmap_entry_t **)(uintptr_t)js_getnum(ptr->u.data.value); 324} 325 326static weakset_entry_t **get_weakset_from_obj(ant_value_t obj) { 327 ant_object_t *ptr = js_obj_ptr(obj); 328 if (!ptr || ptr->type_tag != T_WEAKSET) return NULL; 329 return (weakset_entry_t **)(uintptr_t)js_getnum(ptr->u.data.value); 330} 331 332static map_iterator_state_t *get_map_iter_state(ant_value_t obj) { 333 ant_value_t state_val = js_get_slot(obj, SLOT_ITER_STATE); 334 if (vtype(state_val) == T_UNDEF) return NULL; 335 return (map_iterator_state_t *)(uintptr_t)js_getnum(state_val); 336} 337 338static set_iterator_state_t *get_set_iter_state(ant_value_t obj) { 339 ant_value_t state_val = js_get_slot(obj, SLOT_ITER_STATE); 340 if (vtype(state_val) == T_UNDEF) return NULL; 341 return (set_iterator_state_t *)(uintptr_t)js_getnum(state_val); 342} 343 344static ant_value_t map_set(ant_t *js, ant_value_t *args, int nargs) { 345 if (nargs < 2) return js_mkerr(js, "Map.set() requires 2 arguments"); 346 347 ant_value_t this_val = js->this_val; 348 map_entry_t **map_ptr = get_map_from_obj(this_val); 349 if (!map_ptr) return js_mkerr(js, "Invalid Map object"); 350 351 ant_value_t key_val = normalize_map_key(args[0]); 352 if (!map_store_entry(js, map_ptr, args[0], key_val, args[1])) 353 return js_mkerr(js, "out of memory"); 354 355 ant_object_t *map_obj = js_obj_ptr(this_val); 356 if (map_obj) { 357 gc_write_barrier(js, map_obj, key_val); 358 gc_write_barrier(js, map_obj, args[1]); 359 } 360 361 return this_val; 362} 363 364static ant_value_t map_get(ant_t *js, ant_value_t *args, int nargs) { 365 if (nargs < 1) return js_mkerr(js, "Map.get() requires 1 argument"); 366 367 ant_value_t this_val = js->this_val; 368 map_entry_t **map_ptr = get_map_from_obj(this_val); 369 if (!map_ptr) return js_mkundef(); 370 371 map_entry_t *entry = map_find_entry(js, map_ptr, args[0]); 372 return entry ? entry->value : js_mkundef(); 373} 374 375static ant_value_t map_has(ant_t *js, ant_value_t *args, int nargs) { 376 if (nargs < 1) return js_mkerr(js, "Map.has() requires 1 argument"); 377 378 ant_value_t this_val = js->this_val; 379 map_entry_t **map_ptr = get_map_from_obj(this_val); 380 381 if (!map_ptr) return js_false; 382 map_entry_t *entry = map_find_entry(js, map_ptr, args[0]); 383 return js_bool(entry != NULL); 384} 385 386static ant_value_t map_upsert(ant_t *js, ant_value_t *args, int nargs) { 387 if (nargs < 3) return js_mkerr(js, "Map.upsert() requires 3 arguments"); 388 389 ant_value_t this_val = js->this_val; 390 map_entry_t **map_ptr = get_map_from_obj(this_val); 391 if (!map_ptr) return js_mkerr(js, "Invalid Map object"); 392 393 ant_value_t update_fn = args[1]; 394 ant_value_t insert_fn = args[2]; 395 if (!is_callable(update_fn)) 396 return js_mkerr_typed(js, JS_ERR_TYPE, "Map.upsert update callback must be callable"); 397 if (!is_callable(insert_fn)) 398 return js_mkerr_typed(js, JS_ERR_TYPE, "Map.upsert insert callback must be callable"); 399 400 map_entry_t *entry = map_find_entry(js, map_ptr, args[0]); 401 ant_value_t value; 402 403 if (entry) { 404 ant_value_t call_args[3] = { entry->value, args[0], this_val }; 405 value = sv_vm_call(js->vm, js, update_fn, js_mkundef(), call_args, 3, NULL, false); 406 } else { 407 ant_value_t call_args[2] = { args[0], this_val }; 408 value = sv_vm_call(js->vm, js, insert_fn, js_mkundef(), call_args, 2, NULL, false); 409 } 410 411 if (is_err(value)) return value; 412 413 ant_value_t key_val = normalize_map_key(args[0]); 414 if (!map_store_entry(js, map_ptr, args[0], key_val, value)) 415 return js_mkerr(js, "out of memory"); 416 417 ant_object_t *map_obj = js_obj_ptr(this_val); 418 if (map_obj) { 419 gc_write_barrier(js, map_obj, key_val); 420 gc_write_barrier(js, map_obj, value); 421 } 422 423 return value; 424} 425 426static ant_value_t map_delete(ant_t *js, ant_value_t *args, int nargs) { 427 if (nargs < 1) return js_mkerr(js, "Map.delete() requires 1 argument"); 428 429 ant_value_t this_val = js->this_val; 430 map_entry_t **map_ptr = get_map_from_obj(this_val); 431 432 if (!map_ptr) return js_false; 433 map_entry_t *entry = map_find_entry(js, map_ptr, args[0]); 434 if (entry) { 435 HASH_DEL(*map_ptr, entry); 436 free(entry->key); 437 free(entry); 438 return js_true; 439 } 440 return js_false; 441} 442 443static ant_value_t map_clear(ant_t *js, ant_value_t *args, int nargs) { 444 ant_value_t this_val = js->this_val; 445 map_entry_t **map_ptr = get_map_from_obj(this_val); 446 if (!map_ptr) return js_mkundef(); 447 448 map_entry_t *entry, *tmp; 449 HASH_ITER(hh, *map_ptr, entry, tmp) { 450 HASH_DEL(*map_ptr, entry); 451 free(entry->key); 452 free(entry); 453 } 454 *map_ptr = NULL; 455 456 return js_mkundef(); 457} 458 459static ant_value_t map_size(ant_t *js, ant_value_t *args, int nargs) { 460 ant_value_t this_val = js->this_val; 461 map_entry_t **map_ptr = get_map_from_obj(this_val); 462 if (!map_ptr) return js_mknum(0); 463 464 return js_mknum((double)HASH_COUNT(*map_ptr)); 465} 466 467static ant_value_t map_forEach(ant_t *js, ant_value_t *args, int nargs) { 468 ant_value_t this_val = js->this_val; 469 map_entry_t **map_ptr = get_map_from_obj(this_val); 470 471 if (nargs < 1 || vtype(args[0]) != T_FUNC) 472 return js_mkerr(js, "forEach requires a callback function"); 473 474 ant_value_t callback = args[0]; 475 476 if (map_ptr && *map_ptr) { 477 map_entry_t *entry, *tmp; 478 HASH_ITER(hh, *map_ptr, entry, tmp) { 479 ant_value_t k = entry->key_val; 480 ant_value_t call_args[3] = { entry->value, k, this_val }; 481 ant_value_t result = sv_vm_call(js->vm, js, callback, js_mkundef(), call_args, 3, NULL, false); 482 if (is_err(result)) return result; 483 }} 484 485 return js_mkundef(); 486} 487 488bool advance_map(ant_t *js, js_iter_t *it, ant_value_t *out) { 489 map_iterator_state_t *state = get_map_iter_state(it->iterator); 490 if (!state || !state->current) return false; 491 492 map_entry_t *entry = state->current; 493 switch (state->type) { 494 case ITER_TYPE_MAP_VALUES: 495 *out = entry->value; 496 break; 497 case ITER_TYPE_MAP_KEYS: 498 *out = entry->key_val; 499 break; 500 case ITER_TYPE_MAP_ENTRIES: { 501 ant_value_t pair = js_mkarr(js); 502 js_arr_push(js, pair, entry->key_val); 503 js_arr_push(js, pair, entry->value); 504 *out = pair; 505 break; 506 } 507 default: *out = js_mkundef(); 508 } 509 510 state->current = entry->hh.next; 511 return true; 512} 513 514static ant_value_t map_iter_next(ant_t *js, ant_value_t *args, int nargs) { 515 js_iter_t it = { .iterator = js->this_val }; 516 ant_value_t value; 517 return js_iter_result(js, advance_map(js, &it, &value), value); 518} 519 520static ant_value_t create_map_iterator(ant_t *js, ant_value_t map_obj, iter_type_t type) { 521 map_entry_t **map_ptr = get_map_from_obj(map_obj); 522 523 map_iterator_state_t *state = ant_calloc(sizeof(map_iterator_state_t)); 524 if (!state) return js_mkerr(js, "out of memory"); 525 526 state->head = map_ptr; 527 state->current = map_ptr ? *map_ptr : NULL; 528 state->type = type; 529 530 ant_value_t iter = js_mkobj(js); 531 js_set_proto_init(iter, g_map_iter_proto); 532 js_set_slot(iter, SLOT_ITER_STATE, ANT_PTR(state)); 533 534 return iter; 535} 536 537static ant_value_t map_values(ant_t *js, ant_value_t *args, int nargs) { 538 (void)args; (void)nargs; 539 return create_map_iterator(js, js->this_val, ITER_TYPE_MAP_VALUES); 540} 541 542static ant_value_t map_keys(ant_t *js, ant_value_t *args, int nargs) { 543 (void)args; (void)nargs; 544 return create_map_iterator(js, js->this_val, ITER_TYPE_MAP_KEYS); 545} 546 547static ant_value_t map_entries(ant_t *js, ant_value_t *args, int nargs) { 548 (void)args; (void)nargs; 549 return create_map_iterator(js, js->this_val, ITER_TYPE_MAP_ENTRIES); 550} 551 552bool advance_set(ant_t *js, js_iter_t *it, ant_value_t *out) { 553 set_iterator_state_t *state = get_set_iter_state(it->iterator); 554 if (!state || !state->current) return false; 555 556 set_entry_t *entry = state->current; 557 if (state->type == ITER_TYPE_SET_ENTRIES) { 558 ant_value_t pair = js_mkarr(js); 559 js_arr_push(js, pair, entry->value); 560 js_arr_push(js, pair, entry->value); 561 *out = pair; 562 } else *out = entry->value; 563 564 state->current = entry->hh.next; 565 return true; 566} 567 568static ant_value_t set_iter_next(ant_t *js, ant_value_t *args, int nargs) { 569 js_iter_t it = { .iterator = js->this_val }; 570 ant_value_t value; 571 return js_iter_result(js, advance_set(js, &it, &value), value); 572} 573 574static ant_value_t create_set_iterator(ant_t *js, ant_value_t set_obj, iter_type_t type) { 575 set_entry_t **set_ptr = get_set_from_obj(set_obj); 576 577 set_iterator_state_t *state = ant_calloc(sizeof(set_iterator_state_t)); 578 if (!state) return js_mkerr(js, "out of memory"); 579 580 state->head = set_ptr; 581 state->current = set_ptr ? *set_ptr : NULL; 582 state->type = type; 583 584 ant_value_t iter = js_mkobj(js); 585 js_set_proto_init(iter, g_set_iter_proto); 586 js_set_slot(iter, SLOT_ITER_STATE, ANT_PTR(state)); 587 588 return iter; 589} 590 591static ant_value_t set_add(ant_t *js, ant_value_t *args, int nargs) { 592 if (nargs < 1) return js_mkerr(js, "Set.add() requires 1 argument"); 593 594 ant_value_t this_val = js->this_val; 595 set_entry_t **set_ptr = get_set_from_obj(this_val); 596 if (!set_ptr) return js_mkerr(js, "Invalid Set object"); 597 598 if (!set_store_entry(js, set_ptr, args[0])) 599 return js_mkerr(js, "out of memory"); 600 601 ant_object_t *set_obj = js_obj_ptr(this_val); 602 if (set_obj) gc_write_barrier(js, set_obj, args[0]); 603 604 return this_val; 605} 606 607static ant_value_t set_has(ant_t *js, ant_value_t *args, int nargs) { 608 if (nargs < 1) return js_mkerr(js, "Set.has() requires 1 argument"); 609 610 ant_value_t this_val = js->this_val; 611 set_entry_t **set_ptr = get_set_from_obj(this_val); 612 if (!set_ptr) return js_false; 613 614 set_entry_t *entry = set_find_entry(js, set_ptr, args[0]); 615 return js_bool(entry != NULL); 616} 617 618static ant_value_t set_delete(ant_t *js, ant_value_t *args, int nargs) { 619 if (nargs < 1) return js_mkerr(js, "Set.delete() requires 1 argument"); 620 621 ant_value_t this_val = js->this_val; 622 set_entry_t **set_ptr = get_set_from_obj(this_val); 623 if (!set_ptr) return js_false; 624 625 set_entry_t *entry = set_find_entry(js, set_ptr, args[0]); 626 627 if (entry) { 628 HASH_DEL(*set_ptr, entry); 629 free(entry->key); 630 free(entry); 631 return js_true; 632 } 633 return js_false; 634} 635 636static ant_value_t set_clear(ant_t *js, ant_value_t *args, int nargs) { 637 (void)args; (void)nargs; 638 ant_value_t this_val = js->this_val; 639 set_entry_t **set_ptr = get_set_from_obj(this_val); 640 if (!set_ptr) return js_mkundef(); 641 642 set_entry_t *entry, *tmp; 643 HASH_ITER(hh, *set_ptr, entry, tmp) { 644 HASH_DEL(*set_ptr, entry); 645 free(entry->key); 646 free(entry); 647 } 648 *set_ptr = NULL; 649 650 return js_mkundef(); 651} 652 653static ant_value_t set_size(ant_t *js, ant_value_t *args, int nargs) { 654 (void)args; (void)nargs; 655 ant_value_t this_val = js->this_val; 656 set_entry_t **set_ptr = get_set_from_obj(this_val); 657 if (!set_ptr) return js_mknum(0); 658 659 return js_mknum((double)HASH_COUNT(*set_ptr)); 660} 661 662static ant_value_t set_values(ant_t *js, ant_value_t *args, int nargs) { 663 (void)args; (void)nargs; 664 return create_set_iterator(js, js->this_val, ITER_TYPE_SET_VALUES); 665} 666 667static ant_value_t set_entries(ant_t *js, ant_value_t *args, int nargs) { 668 (void)args; (void)nargs; 669 return create_set_iterator(js, js->this_val, ITER_TYPE_SET_ENTRIES); 670} 671 672static ant_value_t set_forEach(ant_t *js, ant_value_t *args, int nargs) { 673 ant_value_t this_val = js->this_val; 674 set_entry_t **set_ptr = get_set_from_obj(this_val); 675 676 if (nargs < 1 || vtype(args[0]) != T_FUNC) 677 return js_mkerr(js, "forEach requires a callback function"); 678 679 ant_value_t callback = args[0]; 680 if (set_ptr && *set_ptr) { 681 set_entry_t *entry, *tmp; 682 683 HASH_ITER(hh, *set_ptr, entry, tmp) { 684 ant_value_t call_args[3] = { entry->value, entry->value, this_val }; 685 ant_value_t result = sv_vm_call(js->vm, js, callback, js_mkundef(), call_args, 3, NULL, false); 686 if (is_err(result)) return result; 687 }} 688 689 return js_mkundef(); 690} 691 692static ant_value_t make_set_result(ant_t *js, set_entry_t ***out_set) { 693 ant_value_t set_obj = js_mkobj(js); 694 if (is_err(set_obj)) return set_obj; 695 js_obj_ptr(set_obj)->type_tag = T_SET; 696 697 ant_value_t set_proto = js_get_ctor_proto(js, "Set", 3); 698 if (is_special_object(set_proto)) js_set_proto_init(set_obj, set_proto); 699 700 set_entry_t **set_head = ant_calloc(sizeof(set_entry_t *)); 701 if (!set_head) return js_mkerr(js, "out of memory"); 702 *set_head = NULL; 703 704 js_set_slot(set_obj, SLOT_DATA, ANT_PTR(set_head)); 705 if (out_set) *out_set = set_head; 706 707 return set_obj; 708} 709 710static bool set_result_add(ant_t *js, ant_value_t set_obj, set_entry_t **set_ptr, ant_value_t value) { 711 if (!set_store_entry(js, set_ptr, value)) return false; 712 ant_object_t *obj = js_obj_ptr(set_obj); 713 if (obj) gc_write_barrier(js, obj, value); 714 return true; 715} 716 717static void set_result_delete(ant_t *js, set_entry_t **set_ptr, ant_value_t value) { 718 set_entry_t *entry = set_find_entry(js, set_ptr, value); 719 if (!entry) return; 720 HASH_DEL(*set_ptr, entry); 721 free(entry->key); 722 free(entry); 723} 724 725typedef struct { 726 ant_value_t obj; 727 ant_value_t has; 728 ant_value_t keys; 729 double size; 730} set_record_t; 731 732typedef enum { 733 SET_KEY_CONTINUE, 734 SET_KEY_STOP, 735} set_key_status_t; 736 737typedef set_key_status_t (*set_key_cb)( 738 ant_t *js, 739 ant_value_t value, 740 ant_value_t *result, 741 void *ctx 742); 743 744static ant_value_t get_set_record(ant_t *js, ant_value_t value, const char *method, set_record_t *out) { 745 if (!is_object_type(value)) 746 return js_mkerr_typed(js, JS_ERR_TYPE, "Set.%s() requires a set-like object", method); 747 748 ant_value_t size = js_getprop_fallback(js, value, "size"); 749 if (is_err(size)) return size; 750 751 if (vtype(size) == T_BIGINT || vtype(size) == T_SYMBOL) 752 return js_mkerr_typed(js, JS_ERR_TYPE, "Set.%s() requires a numeric size", method); 753 double num_size = js_to_number(js, size); 754 if (isnan(num_size)) 755 return js_mkerr_typed(js, JS_ERR_TYPE, "Set.%s() requires a numeric size", method); 756 double int_size = (num_size == 0.0 || !isfinite(num_size)) 757 ? num_size 758 : (num_size < 0 ? -floor(-num_size) : floor(num_size)); 759 if (int_size < 0) 760 return js_mkerr_typed(js, JS_ERR_RANGE, "Set.%s() requires a non-negative size", method); 761 762 ant_value_t has = js_getprop_fallback(js, value, "has"); 763 if (is_err(has)) return has; 764 if (!is_callable(has)) 765 return js_mkerr_typed(js, JS_ERR_TYPE, "Set.%s() requires a callable has method", method); 766 767 ant_value_t keys = js_getprop_fallback(js, value, "keys"); 768 if (is_err(keys)) return keys; 769 if (!is_callable(keys)) 770 return js_mkerr_typed(js, JS_ERR_TYPE, "Set.%s() requires a callable keys method", method); 771 772 out->obj = value; 773 out->has = has; 774 out->keys = keys; 775 out->size = int_size; 776 777 return js_mkundef(); 778} 779 780static ant_value_t set_record_has(ant_t *js, set_record_t *record, ant_value_t value, bool *out) { 781 ant_value_t result = sv_vm_call(js->vm, js, record->has, record->obj, &value, 1, NULL, false); 782 if (is_err(result)) return result; 783 *out = js_truthy(js, result); 784 return js_mkundef(); 785} 786 787static ant_value_t set_record_close_keys_iterator(ant_t *js, ant_value_t iterator) { 788 ant_value_t return_fn = js_getprop_fallback(js, iterator, "return"); 789 if (is_err(return_fn)) return return_fn; 790 if (!is_callable(return_fn)) return js_mkundef(); 791 return sv_vm_call(js->vm, js, return_fn, iterator, NULL, 0, NULL, false); 792} 793 794static ant_value_t set_record_for_each_key(ant_t *js, set_record_t *record, set_key_cb cb, void *ctx) { 795 ant_value_t iterator = sv_vm_call(js->vm, js, record->keys, record->obj, NULL, 0, NULL, false); 796 if (is_err(iterator)) return iterator; 797 if (!is_object_type(iterator)) 798 return js_mkerr_typed(js, JS_ERR_TYPE, "Set keys() result is not an iterator"); 799 800 ant_value_t next_fn = js_getprop_fallback(js, iterator, "next"); 801 if (is_err(next_fn)) return next_fn; 802 if (!is_callable(next_fn)) 803 return js_mkerr_typed(js, JS_ERR_TYPE, "Set keys() iterator has no callable next method"); 804 805 while (true) { 806 ant_value_t next = sv_vm_call(js->vm, js, next_fn, iterator, NULL, 0, NULL, false); 807 if (is_err(next)) return next; 808 if (!is_object_type(next)) 809 return js_mkerr_typed(js, JS_ERR_TYPE, "Set keys() iterator result is not an object"); 810 811 ant_value_t done = js_getprop_fallback(js, next, "done"); 812 if (is_err(done)) return done; 813 if (js_truthy(js, done)) return js_mkundef(); 814 815 ant_value_t value = js_getprop_fallback(js, next, "value"); 816 if (is_err(value)) return value; 817 818 ant_value_t result = js_mkundef(); 819 set_key_status_t status = cb(js, value, &result, ctx); 820 821 if (is_err(result)) { 822 ant_value_t close_result = set_record_close_keys_iterator(js, iterator); 823 return is_err(close_result) ? close_result : result; 824 } 825 826 if (status == SET_KEY_STOP) { 827 ant_value_t close_result = set_record_close_keys_iterator(js, iterator); 828 return is_err(close_result) ? close_result : js_mkundef(); 829 } 830 } 831} 832 833typedef struct { 834 ant_value_t out; 835 set_entry_t **out_set; 836} set_build_ctx_t; 837 838static set_key_status_t set_add_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 839 set_build_ctx_t *build = (set_build_ctx_t *)ctx; 840 if (!set_result_add(js, build->out, build->out_set, value)) 841 *result = js_mkerr(js, "out of memory"); 842 return SET_KEY_CONTINUE; 843} 844 845static ant_value_t set_union(ant_t *js, ant_value_t *args, int nargs) { 846 set_entry_t **this_set = get_set_from_obj(js->this_val); 847 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 848 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.union() requires a set-like object"); 849 850 set_record_t other; 851 ant_value_t rec = get_set_record(js, args[0], "union", &other); 852 if (is_err(rec)) return rec; 853 854 set_entry_t **out_set = NULL; 855 ant_value_t out = make_set_result(js, &out_set); 856 if (is_err(out)) return out; 857 set_build_ctx_t build = { out, out_set }; 858 859 set_entry_t *entry, *tmp; 860 HASH_ITER(hh, *this_set, entry, tmp) 861 if (!set_result_add(js, out, out_set, entry->value)) return js_mkerr(js, "out of memory"); 862 ant_value_t result = set_record_for_each_key(js, &other, set_add_key_cb, &build); 863 864 return is_err(result) ? result : out; 865} 866 867typedef struct { 868 ant_value_t out; 869 set_entry_t **out_set; 870 set_entry_t **this_set; 871} set_compare_build_ctx_t; 872 873static set_key_status_t set_intersection_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 874 set_compare_build_ctx_t *build = (set_compare_build_ctx_t *)ctx; 875 if ( 876 set_find_entry(js, build->this_set, value) && 877 !set_result_add(js, build->out, build->out_set, value) 878 ) *result = js_mkerr(js, "out of memory"); 879 return SET_KEY_CONTINUE; 880} 881 882static ant_value_t set_intersection(ant_t *js, ant_value_t *args, int nargs) { 883 set_entry_t **this_set = get_set_from_obj(js->this_val); 884 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 885 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.intersection() requires a set-like object"); 886 887 set_record_t other; 888 ant_value_t rec = get_set_record(js, args[0], "intersection", &other); 889 if (is_err(rec)) return rec; 890 891 set_entry_t **out_set = NULL; 892 ant_value_t out = make_set_result(js, &out_set); 893 if (is_err(out)) return out; 894 895 double this_size = (double)HASH_COUNT(*this_set); 896 if (this_size <= other.size) { 897 set_entry_t *entry, *tmp; 898 HASH_ITER(hh, *this_set, entry, tmp) { 899 bool has = false; 900 ant_value_t result = set_record_has(js, &other, entry->value, &has); 901 if (is_err(result)) return result; 902 if (has && !set_result_add(js, out, out_set, entry->value)) return js_mkerr(js, "out of memory"); 903 } 904 return out; 905 } 906 907 set_compare_build_ctx_t build = { out, out_set, this_set }; 908 ant_value_t result = set_record_for_each_key(js, &other, set_intersection_key_cb, &build); 909 910 return is_err(result) ? result : out; 911} 912 913typedef struct { 914 set_record_t *other; 915 ant_value_t out; 916 set_entry_t **out_set; 917} set_difference_ctx_t; 918 919static ant_value_t set_difference_key_cb(ant_t *js, ant_value_t value, void *ctx) { 920 set_difference_ctx_t *build = (set_difference_ctx_t *)ctx; 921 bool has = false; 922 ant_value_t result = set_record_has(js, build->other, value, &has); 923 if (is_err(result)) return result; 924 if (!has && !set_result_add(js, build->out, build->out_set, value)) return js_mkerr(js, "out of memory"); 925 return js_mkundef(); 926} 927 928static set_key_status_t set_delete_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 929 set_build_ctx_t *build = (set_build_ctx_t *)ctx; 930 set_result_delete(js, build->out_set, value); 931 return SET_KEY_CONTINUE; 932} 933 934static ant_value_t set_difference(ant_t *js, ant_value_t *args, int nargs) { 935 set_entry_t **this_set = get_set_from_obj(js->this_val); 936 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 937 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.difference() requires a set-like object"); 938 939 set_record_t other; 940 ant_value_t rec = get_set_record(js, args[0], "difference", &other); 941 if (is_err(rec)) return rec; 942 943 set_entry_t **out_set = NULL; 944 ant_value_t out = make_set_result(js, &out_set); 945 if (is_err(out)) return out; 946 947 set_entry_t *entry, *tmp; 948 if ((double)HASH_COUNT(*this_set) <= other.size) { 949 set_difference_ctx_t diff = { &other, out, out_set }; 950 HASH_ITER(hh, *this_set, entry, tmp) { 951 ant_value_t result = set_difference_key_cb(js, entry->value, &diff); 952 if (is_err(result)) return result; 953 } 954 return out; 955 } 956 957 HASH_ITER(hh, *this_set, entry, tmp) { 958 if (!set_result_add(js, out, out_set, entry->value)) return js_mkerr(js, "out of memory"); 959 } 960 961 set_build_ctx_t build = { out, out_set }; 962 ant_value_t result = set_record_for_each_key(js, &other, set_delete_key_cb, &build); 963 964 return is_err(result) ? result : out; 965} 966 967typedef struct { 968 ant_value_t out; 969 set_entry_t **out_set; 970 set_entry_t **this_set; 971} set_symdiff_ctx_t; 972 973static set_key_status_t set_symmetric_difference_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 974 set_symdiff_ctx_t *build = (set_symdiff_ctx_t *)ctx; 975 if (set_find_entry(js, build->this_set, value)) { 976 set_result_delete(js, build->out_set, value); 977 } else if (!set_find_entry(js, build->out_set, value)) 978 if (!set_result_add(js, build->out, build->out_set, value)) *result = js_mkerr(js, "out of memory"); 979 return SET_KEY_CONTINUE; 980} 981 982static ant_value_t set_symmetricDifference(ant_t *js, ant_value_t *args, int nargs) { 983 set_entry_t **this_set = get_set_from_obj(js->this_val); 984 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 985 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.symmetricDifference() requires a set-like object"); 986 987 set_record_t other; 988 ant_value_t rec = get_set_record(js, args[0], "symmetricDifference", &other); 989 if (is_err(rec)) return rec; 990 991 set_entry_t **out_set = NULL; 992 ant_value_t out = make_set_result(js, &out_set); 993 if (is_err(out)) return out; 994 995 set_entry_t *entry, *tmp; 996 HASH_ITER(hh, *this_set, entry, tmp) { 997 if (!set_result_add(js, out, out_set, entry->value)) return js_mkerr(js, "out of memory"); 998 } 999 set_symdiff_ctx_t build = { out, out_set, this_set }; 1000 ant_value_t result = set_record_for_each_key(js, &other, set_symmetric_difference_key_cb, &build); 1001 return is_err(result) ? result : out; 1002} 1003 1004static ant_value_t set_isSubsetOf(ant_t *js, ant_value_t *args, int nargs) { 1005 set_entry_t **this_set = get_set_from_obj(js->this_val); 1006 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 1007 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.isSubsetOf() requires a set-like object"); 1008 1009 set_record_t other; 1010 ant_value_t rec = get_set_record(js, args[0], "isSubsetOf", &other); 1011 1012 if (is_err(rec)) return rec; 1013 if ((double)HASH_COUNT(*this_set) > other.size) return js_false; 1014 1015 set_entry_t *entry, *tmp; 1016 HASH_ITER(hh, *this_set, entry, tmp) { 1017 bool has = false; 1018 ant_value_t result = set_record_has(js, &other, entry->value, &has); 1019 if (is_err(result)) return result; 1020 if (!has) return js_false; 1021 } 1022 return js_true; 1023} 1024 1025typedef struct { 1026 set_entry_t **this_set; 1027 bool result; 1028} set_predicate_ctx_t; 1029 1030static set_key_status_t set_superset_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 1031 set_predicate_ctx_t *pred = (set_predicate_ctx_t *)ctx; 1032 if (!set_find_entry(js, pred->this_set, value)) { 1033 pred->result = false; 1034 return SET_KEY_STOP; 1035 } 1036 return SET_KEY_CONTINUE; 1037} 1038 1039static ant_value_t set_isSupersetOf(ant_t *js, ant_value_t *args, int nargs) { 1040 set_entry_t **this_set = get_set_from_obj(js->this_val); 1041 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 1042 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.isSupersetOf() requires a set-like object"); 1043 1044 set_record_t other; 1045 ant_value_t rec = get_set_record(js, args[0], "isSupersetOf", &other); 1046 if (is_err(rec)) return rec; 1047 if ((double)HASH_COUNT(*this_set) < other.size) return js_false; 1048 1049 set_predicate_ctx_t pred = { this_set, true }; 1050 ant_value_t result = set_record_for_each_key(js, &other, set_superset_key_cb, &pred); 1051 if (is_err(result)) return result; 1052 return js_bool(pred.result); 1053} 1054 1055static set_key_status_t set_disjoint_key_cb(ant_t *js, ant_value_t value, ant_value_t *result, void *ctx) { 1056 set_predicate_ctx_t *pred = (set_predicate_ctx_t *)ctx; 1057 if (set_find_entry(js, pred->this_set, value)) { 1058 pred->result = false; 1059 return SET_KEY_STOP; 1060 } 1061 return SET_KEY_CONTINUE; 1062} 1063 1064static ant_value_t set_isDisjointFrom(ant_t *js, ant_value_t *args, int nargs) { 1065 set_entry_t **this_set = get_set_from_obj(js->this_val); 1066 if (!this_set) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid Set object"); 1067 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Set.isDisjointFrom() requires a set-like object"); 1068 1069 set_record_t other; 1070 ant_value_t rec = get_set_record(js, args[0], "isDisjointFrom", &other); 1071 if (is_err(rec)) return rec; 1072 1073 if ((double)HASH_COUNT(*this_set) <= other.size) { 1074 set_entry_t *entry, *tmp; 1075 HASH_ITER(hh, *this_set, entry, tmp) { 1076 bool has = false; 1077 ant_value_t result = set_record_has(js, &other, entry->value, &has); 1078 if (is_err(result)) return result; 1079 if (has) return js_false; 1080 } 1081 return js_true; 1082 } 1083 1084 set_predicate_ctx_t pred = { this_set, true }; 1085 ant_value_t result = set_record_for_each_key(js, &other, set_disjoint_key_cb, &pred); 1086 if (is_err(result)) return result; 1087 1088 return js_bool(pred.result); 1089} 1090 1091static ant_value_t weakmap_set(ant_t *js, ant_value_t *args, int nargs) { 1092 if (nargs < 2) return js_mkerr(js, "WeakMap.set() requires 2 arguments"); 1093 1094 ant_value_t this_val = js->this_val; 1095 weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1096 if (!wm_ptr) return js_mkerr(js, "Invalid WeakMap object"); 1097 1098 if (!is_object_type(args[0])) 1099 return js_mkerr(js, "WeakMap key must be an object"); 1100 1101 ant_value_t key_obj = args[0]; 1102 weakmap_entry_t *entry; 1103 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1104 1105 if (entry) entry->value = args[1]; else { 1106 entry = ant_calloc(sizeof(weakmap_entry_t)); 1107 if (!entry) return js_mkerr(js, "out of memory"); 1108 entry->key_obj = key_obj; 1109 entry->value = args[1]; 1110 HASH_ADD(hh, *wm_ptr, key_obj, sizeof(ant_value_t), entry); 1111 } 1112 1113 ant_object_t *wm_obj = js_obj_ptr(this_val); 1114 if (wm_obj) { 1115 gc_write_barrier(js, wm_obj, key_obj); 1116 gc_write_barrier(js, wm_obj, args[1]); 1117 } 1118 1119 return this_val; 1120} 1121 1122static ant_value_t weakmap_get(ant_t *js, ant_value_t *args, int nargs) { 1123 if (nargs < 1) return js_mkerr(js, "WeakMap.get() requires 1 argument"); 1124 1125 ant_value_t this_val = js->this_val; 1126 weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1127 if (!wm_ptr) return js_mkundef(); 1128 if (!is_object_type(args[0])) return js_mkundef(); 1129 1130 ant_value_t key_obj = args[0]; 1131 weakmap_entry_t *entry; 1132 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1133 return entry ? entry->value : js_mkundef(); 1134} 1135 1136static ant_value_t weakmap_has(ant_t *js, ant_value_t *args, int nargs) { 1137 if (nargs < 1) return js_mkerr(js, "WeakMap.has() requires 1 argument"); 1138 1139 ant_value_t this_val = js->this_val; 1140 weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1141 if (!wm_ptr) return js_false; 1142 if (!is_object_type(args[0])) return js_false; 1143 1144 ant_value_t key_obj = args[0]; 1145 weakmap_entry_t *entry; 1146 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1147 return js_bool(entry != NULL); 1148} 1149 1150static ant_value_t weakmap_upsert(ant_t *js, ant_value_t *args, int nargs) { 1151 if (nargs < 3) return js_mkerr(js, "WeakMap.upsert() requires 3 arguments"); 1152 1153 ant_value_t this_val = js->this_val; 1154 weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1155 if (!wm_ptr) return js_mkerr(js, "Invalid WeakMap object"); 1156 1157 if (!is_object_type(args[0])) 1158 return js_mkerr(js, "WeakMap key must be an object"); 1159 1160 ant_value_t update_fn = args[1]; 1161 ant_value_t insert_fn = args[2]; 1162 if (!is_callable(update_fn)) 1163 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap.upsert update callback must be callable"); 1164 if (!is_callable(insert_fn)) 1165 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap.upsert insert callback must be callable"); 1166 1167 ant_value_t key_obj = args[0]; 1168 weakmap_entry_t *entry; 1169 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1170 1171 ant_value_t value; 1172 if (entry) { 1173 ant_value_t call_args[3] = { entry->value, key_obj, this_val }; 1174 value = sv_vm_call(js->vm, js, update_fn, js_mkundef(), call_args, 3, NULL, false); 1175 } else { 1176 ant_value_t call_args[2] = { key_obj, this_val }; 1177 value = sv_vm_call(js->vm, js, insert_fn, js_mkundef(), call_args, 2, NULL, false); 1178 } 1179 1180 if (is_err(value)) return value; 1181 1182 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1183 if (entry) entry->value = value; else { 1184 entry = ant_calloc(sizeof(weakmap_entry_t)); 1185 if (!entry) return js_mkerr(js, "out of memory"); 1186 entry->key_obj = key_obj; 1187 entry->value = value; 1188 HASH_ADD(hh, *wm_ptr, key_obj, sizeof(ant_value_t), entry); 1189 } 1190 1191 ant_object_t *wm_obj = js_obj_ptr(this_val); 1192 if (wm_obj) { 1193 gc_write_barrier(js, wm_obj, key_obj); 1194 gc_write_barrier(js, wm_obj, value); 1195 } 1196 1197 return value; 1198} 1199 1200static ant_value_t weakmap_delete(ant_t *js, ant_value_t *args, int nargs) { 1201 if (nargs < 1) return js_mkerr(js, "WeakMap.delete() requires 1 argument"); 1202 1203 ant_value_t this_val = js->this_val; 1204 weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1205 if (!wm_ptr) return js_false; 1206 if (!is_object_type(args[0])) return js_false; 1207 1208 ant_value_t key_obj = args[0]; 1209 weakmap_entry_t *entry; 1210 HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1211 if (entry) { 1212 HASH_DEL(*wm_ptr, entry); 1213 free(entry); 1214 return js_true; 1215 } 1216 return js_false; 1217} 1218 1219static ant_value_t weakset_add(ant_t *js, ant_value_t *args, int nargs) { 1220 if (nargs < 1) return js_mkerr(js, "WeakSet.add() requires 1 argument"); 1221 1222 ant_value_t this_val = js->this_val; 1223 weakset_entry_t **ws_ptr = get_weakset_from_obj(this_val); 1224 if (!ws_ptr) return js_mkerr(js, "Invalid WeakSet object"); 1225 1226 if (!is_object_type(args[0])) 1227 return js_mkerr(js, "WeakSet value must be an object"); 1228 1229 ant_value_t value_obj = args[0]; 1230 1231 weakset_entry_t *entry; 1232 HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(ant_value_t), entry); 1233 1234 if (!entry) { 1235 entry = ant_calloc(sizeof(weakset_entry_t)); 1236 if (!entry) return js_mkerr(js, "out of memory"); 1237 entry->value_obj = value_obj; 1238 HASH_ADD(hh, *ws_ptr, value_obj, sizeof(ant_value_t), entry); 1239 } 1240 1241 return this_val; 1242} 1243 1244static ant_value_t weakset_has(ant_t *js, ant_value_t *args, int nargs) { 1245 if (nargs < 1) return js_mkerr(js, "WeakSet.has() requires 1 argument"); 1246 1247 ant_value_t this_val = js->this_val; 1248 weakset_entry_t **ws_ptr = get_weakset_from_obj(this_val); 1249 if (!ws_ptr) return js_false; 1250 if (!is_object_type(args[0])) return js_false; 1251 1252 ant_value_t value_obj = args[0]; 1253 weakset_entry_t *entry; 1254 HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(ant_value_t), entry); 1255 return js_bool(entry != NULL); 1256} 1257 1258static ant_value_t weakset_delete(ant_t *js, ant_value_t *args, int nargs) { 1259 if (nargs < 1) return js_mkerr(js, "WeakSet.delete() requires 1 argument"); 1260 1261 ant_value_t this_val = js->this_val; 1262 weakset_entry_t **ws_ptr = get_weakset_from_obj(this_val); 1263 if (!ws_ptr) return js_false; 1264 if (!is_object_type(args[0])) return js_false; 1265 1266 ant_value_t value_obj = args[0]; 1267 weakset_entry_t *entry; 1268 HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(ant_value_t), entry); 1269 1270 if (entry) { 1271 HASH_DEL(*ws_ptr, entry); 1272 free(entry); 1273 return js_true; 1274 } 1275 return js_false; 1276} 1277 1278static ant_value_t builtin_WeakRef(ant_t *js, ant_value_t *args, int nargs) { 1279 if (nargs < 1 || !is_object_type(args[0])) { 1280 return js_mkerr(js, "WeakRef target must be an object"); 1281 } 1282 1283 ant_value_t wr_obj = js_mkobj(js); 1284 ant_value_t wr_proto = js_get_ctor_proto(js, "WeakRef", 7); 1285 if (is_special_object(wr_proto)) js_set_proto_init(wr_obj, wr_proto); 1286 js_set_slot(wr_obj, SLOT_DATA, args[0]); 1287 1288 return wr_obj; 1289} 1290 1291static ant_value_t weakref_deref(ant_t *js, ant_value_t *args, int nargs) { 1292 (void)args; (void)nargs; 1293 ant_value_t this_val = js->this_val; 1294 if (vtype(this_val) != T_OBJ) return js_mkundef(); 1295 1296 ant_value_t target = js_get_slot(this_val, SLOT_DATA); 1297 if (vtype(target) != T_OBJ) return js_mkundef(); 1298 1299 return target; 1300} 1301 1302static ant_value_t builtin_FinalizationRegistry(ant_t *js, ant_value_t *args, int nargs) { 1303 if (nargs < 1 || (vtype(args[0]) != T_FUNC && vtype(args[0]) != T_CFUNC)) { 1304 return js_mkerr(js, "FinalizationRegistry callback must be a function"); 1305 } 1306 1307 ant_value_t fr_obj = js_mkobj(js); 1308 ant_value_t fr_proto = js_get_ctor_proto(js, "FinalizationRegistry", 20); 1309 if (is_special_object(fr_proto)) js_set_proto_init(fr_obj, fr_proto); 1310 1311 js_set_slot(fr_obj, SLOT_MAP, js_mkarr(js)); 1312 js_set_slot(fr_obj, SLOT_DATA, args[0]); 1313 1314 return fr_obj; 1315} 1316 1317static ant_value_t finreg_register(ant_t *js, ant_value_t *args, int nargs) { 1318 ant_value_t this_val = js->this_val; 1319 if (vtype(this_val) != T_OBJ) return js_mkundef(); 1320 1321 if (nargs < 1 || vtype(args[0]) != T_OBJ) { 1322 return js_mkerr(js, "FinalizationRegistry.register target must be an object"); 1323 } 1324 1325 ant_value_t target = args[0]; 1326 ant_value_t held_value = nargs > 1 ? args[1] : js_mkundef(); 1327 ant_value_t unregister_token = nargs > 2 ? args[2] : js_mkundef(); 1328 1329 if (vdata(target) == vdata(held_value) && vtype(held_value) == T_OBJ) { 1330 return js_mkerr(js, "target and held value must not be the same"); 1331 } 1332 1333 ant_value_t registrations = js_get_slot(this_val, SLOT_MAP); 1334 if (vtype(registrations) != T_ARR) return js_mkundef(); 1335 1336 ant_value_t entry = js_mkarr(js); 1337 ant_offset_t len = js_arr_len(js, registrations); 1338 1339 char idx[16]; 1340 size_t idx_len = uint_to_str(idx, sizeof(idx), 0); 1341 js_setprop(js, entry, js_mkstr(js, idx, idx_len), target); 1342 idx_len = uint_to_str(idx, sizeof(idx), 1); 1343 js_setprop(js, entry, js_mkstr(js, idx, idx_len), held_value); 1344 idx_len = uint_to_str(idx, sizeof(idx), 2); 1345 js_setprop(js, entry, js_mkstr(js, idx, idx_len), unregister_token); 1346 js_setprop(js, entry, js->length_str, tov(3.0)); 1347 1348 idx_len = uint_to_str(idx, sizeof(idx), len); 1349 js_setprop(js, registrations, js_mkstr(js, idx, idx_len), entry); 1350 js_setprop(js, registrations, js->length_str, tov((double)(len + 1))); 1351 1352 return js_mkundef(); 1353} 1354 1355static ant_value_t finreg_unregister(ant_t *js, ant_value_t *args, int nargs) { 1356 ant_value_t this_val = js->this_val; 1357 if (vtype(this_val) != T_OBJ) return js_false; 1358 1359 if (nargs < 1 || vtype(args[0]) != T_OBJ) { 1360 return js_mkerr(js, "FinalizationRegistry.unregister token must be an object"); 1361 } 1362 1363 ant_value_t token = args[0]; 1364 ant_value_t registrations = js_get_slot(this_val, SLOT_MAP); 1365 if (vtype(registrations) != T_ARR) return js_false; 1366 1367 ant_offset_t len = js_arr_len(js, registrations); 1368 bool removed = false; 1369 1370 for (ant_offset_t i = 0; i < len; i++) { 1371 ant_value_t entry = js_arr_get(js, registrations, i); 1372 if (vtype(entry) != T_ARR) continue; 1373 ant_value_t entry_token = js_arr_get(js, entry, 2); 1374 if (vtype(entry_token) == T_OBJ && vdata(entry_token) == vdata(token)) { 1375 char idx[16]; 1376 size_t idx_len = uint_to_str(idx, sizeof(idx), i); 1377 js_setprop(js, registrations, js_mkstr(js, idx, idx_len), js_mkundef()); 1378 removed = true; 1379 } 1380 } 1381 1382 return js_bool(removed); 1383} 1384 1385static ant_value_t map_groupBy(ant_t *js, ant_value_t *args, int nargs) { 1386 if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "Map.groupBy requires 2 arguments"); 1387 1388 ant_value_t items = args[0]; 1389 ant_value_t callback = args[1]; 1390 1391 if (vtype(callback) != T_FUNC && vtype(callback) != T_CFUNC) 1392 return js_mkerr_typed(js, JS_ERR_TYPE, "callback is not a function"); 1393 1394 ant_value_t map_obj = js_mkobj(js); 1395 js_obj_ptr(map_obj)->type_tag = T_MAP; 1396 1397 ant_value_t map_proto = js_get_ctor_proto(js, "Map", 3); 1398 if (is_special_object(map_proto)) js_set_proto_init(map_obj, map_proto); 1399 1400 map_entry_t **map_head = ant_calloc(sizeof(map_entry_t *)); 1401 if (!map_head) return js_mkerr(js, "out of memory"); 1402 *map_head = NULL; 1403 js_set_slot(map_obj, SLOT_DATA, ANT_PTR(map_head)); 1404 1405 ant_offset_t len = js_arr_len(js, items); 1406 for (ant_offset_t i = 0; i < len; i++) { 1407 ant_value_t val = js_arr_get(js, items, i); 1408 ant_value_t cb_args[2] = { val, tov((double)i) }; 1409 1410 ant_value_t key = normalize_map_key( 1411 sv_vm_call(js->vm, js, callback, 1412 js_mkundef(), cb_args, 2, NULL, false) 1413 ); 1414 1415 if (is_err(key)) return key; 1416 map_entry_t *entry = map_find_entry(js, map_head, key); 1417 ant_value_t group; 1418 1419 if (entry) group = entry->value; else { 1420 group = js_mkarr(js); 1421 if (!map_store_entry(js, map_head, key, key, group)) return js_mkerr(js, "out of memory"); 1422 } 1423 1424 js_arr_push(js, group, val); 1425 } 1426 1427 return map_obj; 1428} 1429 1430static ant_value_t builtin_Map(ant_t *js, ant_value_t *args, int nargs) { 1431 if (vtype(js->new_target) == T_UNDEF) { 1432 return js_mkerr_typed(js, JS_ERR_TYPE, "Map constructor requires 'new'"); 1433 } 1434 1435 ant_value_t map_obj = js->this_val; 1436 if (vtype(map_obj) != T_OBJ) map_obj = js_mkobj(js); 1437 if (is_err(map_obj)) return map_obj; 1438 js_obj_ptr(map_obj)->type_tag = T_MAP; 1439 1440 ant_value_t map_proto = js_get_ctor_proto(js, "Map", 3); 1441 ant_value_t instance_proto = js_instance_proto_from_new_target(js, map_proto); 1442 1443 if (is_special_object(instance_proto)) js_set_proto_init(map_obj, instance_proto); 1444 1445 map_entry_t **map_head = ant_calloc(sizeof(map_entry_t *)); 1446 if (!map_head) return js_mkerr(js, "out of memory"); 1447 *map_head = NULL; 1448 1449 if (vtype(js->new_target) == T_FUNC || vtype(js->new_target) == T_CFUNC) 1450 js_set_slot(map_obj, SLOT_CTOR, js->new_target); 1451 js_set_slot(map_obj, SLOT_DATA, ANT_PTR(map_head)); 1452 1453 if (nargs == 0 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) return map_obj; 1454 ant_value_t init_result = map_init_from_iterable(js, map_head, args[0]); 1455 if (is_err(init_result)) return init_result; 1456 1457 return map_obj; 1458} 1459 1460static ant_value_t builtin_Set(ant_t *js, ant_value_t *args, int nargs) { 1461 if (vtype(js->new_target) == T_UNDEF) { 1462 return js_mkerr_typed(js, JS_ERR_TYPE, "Set constructor requires 'new'"); 1463 } 1464 1465 ant_value_t set_obj = js->this_val; 1466 if (vtype(set_obj) != T_OBJ) set_obj = js_mkobj(js); 1467 if (is_err(set_obj)) return set_obj; 1468 js_obj_ptr(set_obj)->type_tag = T_SET; 1469 1470 ant_value_t set_proto = js_get_ctor_proto(js, "Set", 3); 1471 ant_value_t instance_proto = js_instance_proto_from_new_target(js, set_proto); 1472 1473 if (is_special_object(instance_proto)) js_set_proto_init(set_obj, instance_proto); 1474 1475 set_entry_t **set_head = ant_calloc(sizeof(set_entry_t *)); 1476 if (!set_head) return js_mkerr(js, "out of memory"); 1477 *set_head = NULL; 1478 1479 if (vtype(js->new_target) == T_FUNC || vtype(js->new_target) == T_CFUNC) 1480 js_set_slot(set_obj, SLOT_CTOR, js->new_target); 1481 js_set_slot(set_obj, SLOT_DATA, ANT_PTR(set_head)); 1482 1483 if (nargs == 0 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) return set_obj; 1484 ant_value_t init_result = set_init_from_iterable(js, set_head, args[0]); 1485 if (is_err(init_result)) return init_result; 1486 1487 return set_obj; 1488} 1489 1490static ant_value_t builtin_WeakMap(ant_t *js, ant_value_t *args, int nargs) { 1491 if (vtype(js->new_target) == T_UNDEF) { 1492 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap constructor requires 'new'"); 1493 } 1494 1495 ant_value_t wm_obj = js->this_val; 1496 if (vtype(wm_obj) != T_OBJ) wm_obj = js_mkobj(js); 1497 if (is_err(wm_obj)) return wm_obj; 1498 js_obj_ptr(wm_obj)->type_tag = T_WEAKMAP; 1499 1500 ant_value_t wm_proto = js_get_ctor_proto(js, "WeakMap", 7); 1501 ant_value_t instance_proto = js_instance_proto_from_new_target(js, wm_proto); 1502 1503 if (is_special_object(instance_proto)) js_set_proto_init(wm_obj, instance_proto); 1504 1505 weakmap_entry_t **wm_head = ant_calloc(sizeof(weakmap_entry_t *)); 1506 if (!wm_head) return js_mkerr(js, "out of memory"); 1507 *wm_head = NULL; 1508 1509 if (vtype(js->new_target) == T_FUNC || vtype(js->new_target) == T_CFUNC) 1510 js_set_slot(wm_obj, SLOT_CTOR, js->new_target); 1511 js_set_slot(wm_obj, SLOT_DATA, ANT_PTR(wm_head)); 1512 1513 if (nargs == 0 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) return wm_obj; 1514 ant_value_t init_result = weakmap_init_from_iterable(js, wm_head, args[0]); 1515 if (is_err(init_result)) return init_result; 1516 1517 return wm_obj; 1518} 1519 1520static ant_value_t builtin_WeakSet(ant_t *js, ant_value_t *args, int nargs) { 1521 if (vtype(js->new_target) == T_UNDEF) { 1522 return js_mkerr_typed(js, JS_ERR_TYPE, "WeakSet constructor requires 'new'"); 1523 } 1524 1525 ant_value_t ws_obj = js->this_val; 1526 if (vtype(ws_obj) != T_OBJ) ws_obj = js_mkobj(js); 1527 if (is_err(ws_obj)) return ws_obj; 1528 js_obj_ptr(ws_obj)->type_tag = T_WEAKSET; 1529 1530 ant_value_t ws_proto = js_get_ctor_proto(js, "WeakSet", 7); 1531 ant_value_t instance_proto = js_instance_proto_from_new_target(js, ws_proto); 1532 1533 if (is_special_object(instance_proto)) js_set_proto_init(ws_obj, instance_proto); 1534 1535 weakset_entry_t **ws_head = ant_calloc(sizeof(weakset_entry_t *)); 1536 if (!ws_head) return js_mkerr(js, "out of memory"); 1537 *ws_head = NULL; 1538 1539 if (vtype(js->new_target) == T_FUNC || vtype(js->new_target) == T_CFUNC) 1540 js_set_slot(ws_obj, SLOT_CTOR, js->new_target); 1541 js_set_slot(ws_obj, SLOT_DATA, ANT_PTR(ws_head)); 1542 1543 if (nargs == 0 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) return ws_obj; 1544 ant_value_t init_result = weakset_init_from_iterable(js, ws_head, args[0]); 1545 if (is_err(init_result)) return init_result; 1546 1547 return ws_obj; 1548} 1549 1550void init_collections_module(void) { 1551 ant_t *js = rt->js; 1552 1553 ant_value_t glob = js->global; 1554 ant_value_t object_proto = js->sym.object_proto; 1555 1556 ant_value_t iter_sym = get_iterator_sym(); 1557 ant_value_t tag_sym = get_toStringTag_sym(); 1558 1559 g_map_iter_proto = js_mkobj(js); 1560 js_set_proto_init(g_map_iter_proto, js->sym.iterator_proto); 1561 js_set(js, g_map_iter_proto, "next", js_mkfun(map_iter_next)); 1562 js_iter_register_advance(g_map_iter_proto, advance_map); 1563 1564 g_set_iter_proto = js_mkobj(js); 1565 js_set_proto_init(g_set_iter_proto, js->sym.iterator_proto); 1566 js_set(js, g_set_iter_proto, "next", js_mkfun(set_iter_next)); 1567 js_iter_register_advance(g_set_iter_proto, advance_set); 1568 1569 ant_value_t map_proto = js_mkobj(js); 1570 js_set_proto_init(map_proto, object_proto); 1571 js_set(js, map_proto, "set", js_mkfun(map_set)); 1572 js_set(js, map_proto, "get", js_mkfun(map_get)); 1573 js_set(js, map_proto, "has", js_mkfun(map_has)); 1574 js_set(js, map_proto, "upsert", js_mkfun(map_upsert)); 1575 js_set(js, map_proto, "delete", js_mkfun(map_delete)); 1576 js_set(js, map_proto, "clear", js_mkfun(map_clear)); 1577 js_set_getter_desc(js, map_proto, "size", 4, js_mkfun(map_size), JS_DESC_C); 1578 js_set(js, map_proto, "entries", js_mkfun(map_entries)); 1579 js_set(js, map_proto, "keys", js_mkfun(map_keys)); 1580 js_set(js, map_proto, "values", js_mkfun(map_values)); 1581 js_set(js, map_proto, "forEach", js_mkfun(map_forEach)); 1582 js_set_sym(js, map_proto, iter_sym, js_get(js, map_proto, "entries")); 1583 js_set_sym(js, map_proto, tag_sym, js_mkstr(js, "Map", 3)); 1584 1585 ant_value_t map_ctor = js_mkobj(js); 1586 js_set_slot(map_ctor, SLOT_CFUNC, js_mkfun(builtin_Map)); 1587 js_mkprop_fast(js, map_ctor, "prototype", 9, map_proto); 1588 js_mkprop_fast(js, map_ctor, "name", 4, ANT_STRING("Map")); 1589 js_set_descriptor(js, map_ctor, "name", 4, 0); 1590 js_set(js, map_ctor, "groupBy", js_mkfun(map_groupBy)); 1591 js_define_species_getter(js, map_ctor); 1592 js_set(js, glob, "Map", js_obj_to_func(map_ctor)); 1593 1594 ant_value_t set_proto = js_mkobj(js); 1595 js_set_proto_init(set_proto, object_proto); 1596 js_set(js, set_proto, "add", js_mkfun(set_add)); 1597 js_set(js, set_proto, "has", js_mkfun(set_has)); 1598 js_set(js, set_proto, "delete", js_mkfun(set_delete)); 1599 js_set(js, set_proto, "clear", js_mkfun(set_clear)); 1600 js_set_getter_desc(js, set_proto, "size", 4, js_mkfun(set_size), JS_DESC_C); 1601 js_set(js, set_proto, "values", js_mkfun(set_values)); 1602 js_set_exact(js, set_proto, "keys", js_get(js, set_proto, "values")); 1603 js_set(js, set_proto, "entries", js_mkfun(set_entries)); 1604 js_set(js, set_proto, "forEach", js_mkfun(set_forEach)); 1605 js_set(js, set_proto, "union", js_mkfun(set_union)); 1606 js_set(js, set_proto, "intersection", js_mkfun(set_intersection)); 1607 js_set(js, set_proto, "difference", js_mkfun(set_difference)); 1608 js_set(js, set_proto, "symmetricDifference", js_mkfun(set_symmetricDifference)); 1609 js_set(js, set_proto, "isSubsetOf", js_mkfun(set_isSubsetOf)); 1610 js_set(js, set_proto, "isSupersetOf", js_mkfun(set_isSupersetOf)); 1611 js_set(js, set_proto, "isDisjointFrom", js_mkfun(set_isDisjointFrom)); 1612 js_set_sym(js, set_proto, iter_sym, js_get(js, set_proto, "values")); 1613 js_set_sym(js, set_proto, tag_sym, js_mkstr(js, "Set", 3)); 1614 1615 ant_value_t set_ctor = js_mkobj(js); 1616 js_set_slot(set_ctor, SLOT_CFUNC, js_mkfun(builtin_Set)); 1617 js_mkprop_fast(js, set_ctor, "prototype", 9, set_proto); 1618 js_mkprop_fast(js, set_ctor, "name", 4, ANT_STRING("Set")); 1619 js_set_descriptor(js, set_ctor, "name", 4, 0); 1620 js_define_species_getter(js, set_ctor); 1621 js_set(js, glob, "Set", js_obj_to_func(set_ctor)); 1622 1623 ant_value_t weakmap_proto = js_mkobj(js); 1624 js_set_proto_init(weakmap_proto, object_proto); 1625 js_set(js, weakmap_proto, "set", js_mkfun(weakmap_set)); 1626 js_set(js, weakmap_proto, "get", js_mkfun(weakmap_get)); 1627 js_set(js, weakmap_proto, "has", js_mkfun(weakmap_has)); 1628 js_set(js, weakmap_proto, "upsert", js_mkfun(weakmap_upsert)); 1629 js_set(js, weakmap_proto, "delete", js_mkfun(weakmap_delete)); 1630 js_set_sym(js, weakmap_proto, tag_sym, js_mkstr(js, "WeakMap", 7)); 1631 1632 ant_value_t weakmap_ctor = js_mkobj(js); 1633 js_set_slot(weakmap_ctor, SLOT_CFUNC, js_mkfun(builtin_WeakMap)); 1634 js_mkprop_fast(js, weakmap_ctor, "prototype", 9, weakmap_proto); 1635 js_mkprop_fast(js, weakmap_ctor, "name", 4, ANT_STRING("WeakMap")); 1636 js_set_descriptor(js, weakmap_ctor, "name", 4, 0); 1637 js_set(js, glob, "WeakMap", js_obj_to_func(weakmap_ctor)); 1638 1639 ant_value_t weakset_proto = js_mkobj(js); 1640 js_set_proto_init(weakset_proto, object_proto); 1641 js_set(js, weakset_proto, "add", js_mkfun(weakset_add)); 1642 js_set(js, weakset_proto, "has", js_mkfun(weakset_has)); 1643 js_set(js, weakset_proto, "delete", js_mkfun(weakset_delete)); 1644 js_set_sym(js, weakset_proto, tag_sym, js_mkstr(js, "WeakSet", 7)); 1645 1646 ant_value_t weakset_ctor = js_mkobj(js); 1647 js_set_slot(weakset_ctor, SLOT_CFUNC, js_mkfun(builtin_WeakSet)); 1648 js_mkprop_fast(js, weakset_ctor, "prototype", 9, weakset_proto); 1649 js_mkprop_fast(js, weakset_ctor, "name", 4, ANT_STRING("WeakSet")); 1650 js_set_descriptor(js, weakset_ctor, "name", 4, 0); 1651 js_set(js, glob, "WeakSet", js_obj_to_func(weakset_ctor)); 1652 1653 ant_value_t weakref_proto = js_mkobj(js); 1654 js_set_proto_init(weakref_proto, object_proto); 1655 js_set(js, weakref_proto, "deref", js_mkfun(weakref_deref)); 1656 js_set_sym(js, weakref_proto, tag_sym, js_mkstr(js, "WeakRef", 7)); 1657 1658 ant_value_t weakref_ctor = js_mkobj(js); 1659 js_set_slot(weakref_ctor, SLOT_CFUNC, js_mkfun(builtin_WeakRef)); 1660 js_mkprop_fast(js, weakref_ctor, "prototype", 9, weakref_proto); 1661 js_mkprop_fast(js, weakref_ctor, "name", 4, ANT_STRING("WeakRef")); 1662 js_set_descriptor(js, weakref_ctor, "name", 4, 0); 1663 js_set(js, glob, "WeakRef", js_obj_to_func(weakref_ctor)); 1664 1665 ant_value_t finreg_proto = js_mkobj(js); 1666 js_set_proto_init(finreg_proto, object_proto); 1667 js_set(js, finreg_proto, "register", js_mkfun(finreg_register)); 1668 js_set(js, finreg_proto, "unregister", js_mkfun(finreg_unregister)); 1669 js_set_sym(js, finreg_proto, tag_sym, js_mkstr(js, "FinalizationRegistry", 20)); 1670 1671 ant_value_t finreg_ctor = js_mkobj(js); 1672 js_set_slot(finreg_ctor, SLOT_CFUNC, js_mkfun(builtin_FinalizationRegistry)); 1673 js_mkprop_fast(js, finreg_ctor, "prototype", 9, finreg_proto); 1674 js_mkprop_fast(js, finreg_ctor, "name", 4, ANT_STRING("FinalizationRegistry")); 1675 js_set_descriptor(js, finreg_ctor, "name", 4, 0); 1676 js_set(js, glob, "FinalizationRegistry", js_obj_to_func(finreg_ctor)); 1677}