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.

implement dense arrays

+1055 -1027
+1
include/common.h
··· 56 56 SLOT_NO_FUNC_DECLS, 57 57 SLOT_ITER_STATE, 58 58 SLOT_ENTRIES, 59 + SLOT_DENSE_BUF, 59 60 SLOT_MAX = 255 60 61 } internal_slot_t; 61 62
+9 -3
include/internal.h
··· 95 95 T_BIGINT, T_PROPREF, T_SYMBOL, T_GENERATOR, T_FFI 96 96 }; 97 97 98 - #define JS_HASH_SIZE 512 99 - #define JS_MAX_PARSE_DEPTH (1024 * 2) 100 - #define JS_ERR_NO_STACK (1 << 8) 98 + #define JS_HASH_SIZE 512 99 + #define JS_MAX_PARSE_DEPTH (1024 * 2) 100 + #define JS_ERR_NO_STACK (1 << 8) 101 + #define JS_DENSE_INITIAL_CAP 8 101 102 102 103 #define NANBOX_PREFIX 0x7FC0000000000000ULL 103 104 #define NANBOX_PREFIX_CHK 0x3FEULL ··· 106 107 #define NANBOX_DATA_MASK 0x0000FFFFFFFFFFFFULL 107 108 108 109 #define TYPE_FLAG(t) (1u << (t)) 110 + #define T_EMPTY (NANBOX_PREFIX | ((jsval_t)T_FFI << NANBOX_TYPE_SHIFT) | 0xDEADULL) 109 111 110 112 #define T_SPECIAL_OBJECT_MASK (TYPE_FLAG(T_OBJ) | TYPE_FLAG(T_ARR)) 111 113 #define T_NEEDS_PROTO_FALLBACK (TYPE_FLAG(T_FUNC) | TYPE_FLAG(T_ARR) | TYPE_FLAG(T_PROMISE)) ··· 157 159 158 160 static inline bool is_undefined(jsval_t v) { 159 161 return vtype(v) == T_UNDEF; 162 + } 163 + 164 + static inline bool is_empty_slot(jsval_t v) { 165 + return v == T_EMPTY; 160 166 } 161 167 162 168 #endif
+834 -1022
src/ant.c
··· 713 713 static jsval_t proxy_aware_get_elem(struct js *js, jsval_t obj, const char *key, size_t key_len); 714 714 static bool bigint_is_zero(struct js *js, jsval_t v); 715 715 716 + static jsoff_t get_dense_buf(struct js *js, jsval_t arr); 717 + static jsoff_t dense_length(struct js *js, jsoff_t doff); 718 + static jsoff_t get_array_length(struct js *js, jsval_t arr); 719 + static jsval_t arr_get(struct js *js, jsval_t arr, jsoff_t idx); 720 + static bool arr_has(struct js *js, jsval_t arr, jsoff_t idx); 721 + 716 722 static bool streq(const char *buf, size_t len, const char *p, size_t n); 717 723 static bool is_this_loop_continue_target(int depth_at_entry); 718 724 static bool code_has_function_decl(const char *code, size_t len); ··· 1038 1044 } 1039 1045 1040 1046 static bool is_small_array(struct js *js, jsval_t obj, int *elem_count) { 1041 - int count = 0; 1042 - bool has_nested = false; 1043 - jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1044 - jsoff_t length = 0; 1045 - jsoff_t scan = next; 1046 - 1047 - while (scan < js->brk && scan != 0) { 1048 - const char *key; jsoff_t klen; 1049 - get_prop_key(js, scan, &key, &klen); 1050 - if (streq(key, klen, "length", 6)) { 1051 - jsval_t val = get_prop_val(js, scan); 1052 - if (vtype(val) == T_NUM) length = (jsoff_t) tod(val); 1053 - break; 1054 - } 1055 - scan = loadoff(js, scan) & ~(3U | FLAGMASK); 1056 - } 1047 + int count = 0; bool has_nested = false; 1048 + jsoff_t length = get_array_length(js, obj); 1057 1049 1058 1050 for (jsoff_t i = 0; i < length; i++) { 1059 - char idx[16]; 1060 - snprintf(idx, sizeof(idx), "%u", (unsigned) i); 1061 - jsoff_t idxlen = (jsoff_t) strlen(idx); 1062 - jsoff_t prop = next; 1063 - jsval_t val = js_mkundef(); 1064 - bool found = false; 1065 - 1066 - while (prop < js->brk && prop != 0) { 1067 - const char *key; jsoff_t klen; 1068 - get_prop_key(js, prop, &key, &klen); 1069 - if (streq(key, klen, idx, idxlen)) { 1070 - val = get_prop_val(js, prop); 1071 - found = true; 1072 - break; 1073 - } 1074 - prop = loadoff(js, prop) & ~(3U | FLAGMASK); 1075 - } 1076 - 1077 - if (found) { 1078 - uint8_t t = vtype(val); 1079 - if (t == T_OBJ || t == T_ARR || t == T_FUNC) has_nested = true; 1080 - count++; 1081 - } else count++; 1051 + jsval_t val = arr_get(js, obj, i); uint8_t t = vtype(val); 1052 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) has_nested = true; 1053 + count++; 1082 1054 } 1083 1055 1084 1056 if (elem_count) *elem_count = count; ··· 1108 1080 } 1109 1081 1110 1082 static jsoff_t get_array_length(struct js *js, jsval_t arr) { 1083 + jsoff_t doff = get_dense_buf(js, arr); 1084 + if (doff) return dense_length(js, doff); 1111 1085 jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 1112 1086 if (!off) return 0; 1113 1087 jsval_t val = resolveprop(js, mkval(T_PROP, off)); ··· 1173 1147 if (i > 0) n += cpy(buf + n, REMAIN(n, len), inline_mode ? ", " : ",\n", 2); 1174 1148 if (!inline_mode) n += add_indent(buf + n, REMAIN(n, len), stringify_indent); 1175 1149 1176 - char idx[16]; 1177 - snprintf(idx, sizeof(idx), "%u", (unsigned) i); 1178 - jsoff_t idxlen = (jsoff_t) strlen(idx); 1179 - 1180 - bool found = false; 1181 - jsval_t val = js_mkundef(); 1182 - for (jsoff_t p = first; p < js->brk && p != 0; p = next_prop(loadoff(js, p))) { 1183 - const char *key; jsoff_t klen; 1184 - get_prop_key(js, p, &key, &klen); 1185 - if (streq(key, klen, idx, idxlen)) { 1186 - val = get_prop_val(js, p); 1187 - found = true; break; 1188 - } 1189 - } 1150 + jsval_t val = arr_get(js, obj, i); bool found = arr_has(js, obj, i); 1190 1151 n += found ? tostr(js, val, buf + n, REMAIN(n, len)) : cpy(buf + n, REMAIN(n, len), "undefined", 9); 1191 1152 } 1192 1153 ··· 1219 1180 static size_t array_to_string(struct js *js, jsval_t obj, char *buf, size_t len) { 1220 1181 if (is_circular(obj)) return cpy(buf, len, "", 0); 1221 1182 1222 - push_stringify(obj); 1223 - size_t n = 0; 1224 - jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1225 - jsoff_t length = 0; 1226 - jsoff_t scan = next; 1227 - 1228 - while (scan < js->brk && scan != 0) { 1229 - const char *key; jsoff_t klen; 1230 - get_prop_key(js, scan, &key, &klen); 1231 - if (streq(key, klen, "length", 6)) { 1232 - jsval_t val = get_prop_val(js, scan); 1233 - if (vtype(val) == T_NUM) length = (jsoff_t) tod(val); 1234 - break; 1235 - } 1236 - scan = loadoff(js, scan) & ~(3U | FLAGMASK); 1237 - } 1183 + push_stringify(obj); size_t n = 0; 1184 + jsoff_t length = get_array_length(js, obj); 1238 1185 1239 1186 for (jsoff_t i = 0; i < length; i++) { 1240 1187 if (i > 0) n += cpy(buf + n, REMAIN(n, len), ",", 1); 1241 - char idx[16]; 1242 - snprintf(idx, sizeof(idx), "%u", (unsigned) i); 1243 - jsoff_t idxlen = (jsoff_t) strlen(idx); 1244 - jsoff_t prop = next; 1245 - jsval_t val = js_mkundef(); 1246 - bool found = false; 1247 - 1248 - while (prop < js->brk && prop != 0) { 1249 - const char *key; jsoff_t klen; 1250 - get_prop_key(js, prop, &key, &klen); 1251 - if (streq(key, klen, idx, idxlen)) { 1252 - val = get_prop_val(js, prop); 1253 - found = true; 1254 - break; 1255 - } 1256 - prop = loadoff(js, prop) & ~(3U | FLAGMASK); 1257 - } 1188 + jsval_t val = arr_get(js, obj, i); 1258 1189 1259 - if (found) { 1190 + if (arr_has(js, obj, i)) { 1260 1191 uint8_t vt = vtype(val); 1261 1192 if (vt == T_STR) { 1262 1193 jsoff_t slen, soff = vstr(js, val, &slen); ··· 2341 2272 return ofs; 2342 2273 } 2343 2274 2275 + static jsoff_t dense_alloc(struct js *js, jsoff_t capacity) { 2276 + jsoff_t size = sizeof(jsoff_t) * 2 + sizeof(jsval_t) * capacity; 2277 + jsoff_t off = js_alloc(js, size); 2278 + if (off == (jsoff_t)~0) return 0; 2279 + 2280 + saveoff(js, off, capacity); 2281 + saveoff(js, off + sizeof(jsoff_t), 0); 2282 + 2283 + for (jsoff_t i = 0; i < capacity; i++) saveval( 2284 + js, off + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * i, T_EMPTY 2285 + ); 2286 + 2287 + return off; 2288 + } 2289 + 2290 + static inline jsoff_t get_dense_buf(struct js *js, jsval_t arr) { 2291 + jsval_t slot = get_slot(js, arr, SLOT_DENSE_BUF); 2292 + if (vtype(slot) == T_UNDEF) return 0; 2293 + return (jsoff_t) tod(slot); 2294 + } 2295 + 2296 + static inline jsoff_t dense_capacity(struct js *js, jsoff_t doff) { 2297 + return loadoff(js, doff); 2298 + } 2299 + 2300 + static inline jsoff_t dense_length(struct js *js, jsoff_t doff) { 2301 + return loadoff(js, doff + sizeof(jsoff_t)); 2302 + } 2303 + 2304 + static inline void dense_set_length(struct js *js, jsoff_t doff, jsoff_t len) { 2305 + saveoff(js, doff + sizeof(jsoff_t), len); 2306 + } 2307 + 2308 + static inline jsval_t dense_get(struct js *js, jsoff_t doff, jsoff_t idx) { 2309 + return loadval(js, doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * idx); 2310 + } 2311 + 2312 + static inline void dense_set(struct js *js, jsoff_t doff, jsoff_t idx, jsval_t val) { 2313 + saveval(js, doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * idx, val); 2314 + } 2315 + 2316 + static jsoff_t dense_grow(struct js *js, jsval_t arr, jsoff_t needed) { 2317 + jsoff_t doff = get_dense_buf(js, arr); 2318 + jsoff_t old_cap = doff ? dense_capacity(js, doff) : 0; 2319 + jsoff_t old_len = doff ? dense_length(js, doff) : 0; 2320 + jsoff_t new_cap = old_cap ? old_cap : JS_DENSE_INITIAL_CAP; 2321 + 2322 + while (new_cap < needed) new_cap *= 2; 2323 + jsoff_t new_doff = dense_alloc(js, new_cap); 2324 + 2325 + if (new_doff == 0) return 0; 2326 + if (doff && old_len > 0) memcpy( 2327 + &js->mem[new_doff + sizeof(jsoff_t) * 2], 2328 + &js->mem[doff + sizeof(jsoff_t) * 2], 2329 + sizeof(jsval_t) * old_len 2330 + ); 2331 + 2332 + dense_set_length(js, new_doff, old_len); 2333 + set_slot(js, arr, SLOT_DENSE_BUF, tov((double)new_doff)); 2334 + 2335 + return new_doff; 2336 + } 2337 + 2338 + static inline jsval_t arr_get(struct js *js, jsval_t arr, jsoff_t idx) { 2339 + jsoff_t doff = get_dense_buf(js, arr); 2340 + 2341 + if (doff) { 2342 + jsoff_t len = dense_length(js, doff); 2343 + if (idx >= len) return js_mkundef(); 2344 + jsval_t v = dense_get(js, doff, idx); 2345 + return is_empty_slot(v) ? js_mkundef() : v; 2346 + } 2347 + 2348 + char idxstr[16]; 2349 + size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 2350 + jsoff_t prop = lkp(js, arr, idxstr, idxlen); 2351 + 2352 + return prop ? resolveprop(js, mkval(T_PROP, prop)) : js_mkundef(); 2353 + } 2354 + 2355 + static inline void arr_set(struct js *js, jsval_t arr, jsoff_t idx, jsval_t val) { 2356 + jsoff_t doff = get_dense_buf(js, arr); 2357 + 2358 + if (doff) { 2359 + jsoff_t cap = dense_capacity(js, doff); 2360 + jsoff_t len = dense_length(js, doff); 2361 + if (idx >= cap) { 2362 + doff = dense_grow(js, arr, idx + 1); 2363 + if (doff == 0) return; 2364 + } 2365 + 2366 + dense_set(js, doff, idx, val); if (idx >= len) { 2367 + for (jsoff_t i = len; i < idx; i++) { 2368 + jsval_t v = dense_get(js, doff, i); 2369 + if (!is_empty_slot(v) && vtype(v) == T_UNDEF) dense_set(js, doff, i, T_EMPTY); 2370 + } dense_set_length(js, doff, idx + 1); 2371 + } 2372 + return; 2373 + } 2374 + 2375 + char idxstr[16]; 2376 + size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 2377 + jsval_t key = js_mkstr(js, idxstr, idxlen); 2378 + 2379 + js_setprop(js, arr, key, val); 2380 + } 2381 + 2382 + static inline bool arr_has(struct js *js, jsval_t arr, jsoff_t idx) { 2383 + jsoff_t doff = get_dense_buf(js, arr); 2384 + 2385 + if (doff) { 2386 + jsoff_t len = dense_length(js, doff); 2387 + if (idx >= len) return false; 2388 + return !is_empty_slot(dense_get(js, doff, idx)); 2389 + } 2390 + 2391 + char idxstr[16]; 2392 + size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 2393 + return lkp(js, arr, idxstr, idxlen) != 0; 2394 + } 2395 + 2396 + static inline void arr_del(struct js *js, jsval_t arr, jsoff_t idx) { 2397 + jsoff_t doff = get_dense_buf(js, arr); 2398 + 2399 + if (doff) { 2400 + jsoff_t len = dense_length(js, doff); 2401 + if (idx < len) dense_set(js, doff, idx, T_EMPTY); 2402 + return; 2403 + } 2404 + 2405 + char idxstr[16]; 2406 + uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 2407 + js_del(js, arr, idxstr); 2408 + } 2409 + 2410 + static inline jsoff_t dense_arr_length(struct js *js, jsval_t arr) { 2411 + jsoff_t doff = get_dense_buf(js, arr); 2412 + if (doff) return dense_length(js, doff); 2413 + return 0; 2414 + } 2415 + 2344 2416 static jsval_t mkentity(struct js *js, jsoff_t b, const void *buf, size_t len) { 2345 2417 jsoff_t ofs = js_alloc(js, len + sizeof(b)); 2346 2418 if (ofs == (jsoff_t) ~0) return js_mkerr(js, "oom"); 2419 + 2347 2420 memcpy(&js->mem[ofs], &b, sizeof(b)); 2348 2421 if (buf != NULL) { 2349 2422 size_t copy_len = ((b & 3) == T_STR && len > 0) ? len - 1 : len; 2350 2423 memmove(&js->mem[ofs + sizeof(b)], buf, copy_len); 2351 2424 } 2425 + 2352 2426 if ((b & 3) == T_STR) js->mem[ofs + sizeof(b) + len - 1] = 0; 2353 2427 return mkval(b & 3, ofs); 2354 2428 } ··· 2945 3019 if (vtype(array_proto) == T_OBJ) set_proto(js, arr, array_proto); 2946 3020 2947 3021 jsval_t arr_val = mkval(T_ARR, vdata(arr)); 2948 - js_set_descriptor(js, arr_val, "length", 6, JS_DESC_W); 3022 + jsoff_t doff = dense_alloc(js, JS_DENSE_INITIAL_CAP); 3023 + if (doff) set_slot(js, arr_val, SLOT_DENSE_BUF, tov((double)doff)); 2949 3024 2950 3025 return arr_val; 2951 3026 } ··· 2963 3038 2964 3039 jsoff_t js_arr_len(struct js *js, jsval_t arr) { 2965 3040 if (vtype(arr) != T_ARR) return 0; 3041 + jsoff_t doff = get_dense_buf(js, arr); 3042 + if (doff) return dense_length(js, doff); 3043 + 2966 3044 jsoff_t max_idx = 0; 2967 3045 bool found_length_prop = false; 2968 3046 jsoff_t length_prop_val = 0; 3047 + 2969 3048 jsoff_t scan = loadoff(js, (jsoff_t) vdata(arr)) & ~(3U | FLAGMASK); 2970 3049 while (scan < js->brk && scan != 0) { 2971 3050 const char *key; jsoff_t klen; ··· 2983 3062 } 2984 3063 scan = loadoff(js, scan) & ~(3U | FLAGMASK); 2985 3064 } 3065 + 2986 3066 if (found_length_prop) return length_prop_val; 2987 3067 return max_idx; 2988 3068 } 2989 3069 2990 3070 jsval_t js_arr_get(struct js *js, jsval_t arr, jsoff_t idx) { 2991 3071 if (vtype(arr) != T_ARR) return js_mkundef(); 2992 - char idxstr[16]; 2993 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 2994 - jsoff_t prop = loadoff(js, (jsoff_t) vdata(arr)) & ~(3U | FLAGMASK); 2995 - while (prop < js->brk && prop != 0) { 2996 - const char *key; jsoff_t klen; 2997 - get_prop_key(js, prop, &key, &klen); 2998 - if (streq(key, klen, idxstr, idxlen)) return get_prop_val(js, prop); 2999 - prop = loadoff(js, prop) & ~(3U | FLAGMASK); 3000 - } 3001 - return js_mkundef(); 3072 + return arr_get(js, arr, idx); 3002 3073 } 3003 3074 3004 3075 static inline bool is_const_prop(struct js *js, jsoff_t propoff) { ··· 3341 3412 } 3342 3413 3343 3414 static inline void update_array_length(struct js *js, jsval_t obj, jsoff_t new_len) { 3415 + jsoff_t doff = get_dense_buf(js, obj); 3416 + if (doff) { dense_set_length(js, doff, new_len); return; } 3417 + 3344 3418 jsoff_t len_off = lkp_interned(js, obj, INTERN_LENGTH, 6); 3345 3419 jsval_t new_len_val = tov((double)new_len); 3346 3420 ··· 3352 3426 unsigned long idx; 3353 3427 if (!parse_array_index(key, klen, (jsoff_t)-1, &idx)) return js_mkundef(); 3354 3428 3429 + jsoff_t doff = get_dense_buf(js, obj); 3430 + if (doff) { 3431 + jsoff_t cur_len = dense_length(js, doff); 3432 + if (idx < cur_len) return js_mkundef(); 3433 + 3434 + jsval_t extensibility_error = check_object_extensibility(js, obj); 3435 + if (!is_undefined(extensibility_error)) return extensibility_error; 3436 + 3437 + arr_set(js, obj, (jsoff_t)idx, v); 3438 + return v; 3439 + } 3440 + 3355 3441 jsoff_t cur_len = get_array_length(js, obj); 3356 3442 if (idx < cur_len) return js_mkundef(); 3357 3443 ··· 3376 3462 if (vtype(obj) == T_ARR && streq(key, klen, "length", 6)) { 3377 3463 jsval_t err = validate_array_length(js, v); 3378 3464 if (is_err(err)) return err; 3465 + jsoff_t doff = get_dense_buf(js, obj); 3466 + if (doff) { 3467 + jsoff_t new_len_val = (jsoff_t) tod(v); 3468 + jsoff_t cur_len = dense_length(js, doff); 3469 + if (new_len_val < cur_len) { 3470 + for (jsoff_t i = new_len_val; i < cur_len; i++) 3471 + dense_set(js, doff, i, T_EMPTY); 3472 + } else if (new_len_val > cur_len) { 3473 + jsoff_t cap = dense_capacity(js, doff); 3474 + if (new_len_val > cap) { 3475 + doff = dense_grow(js, obj, new_len_val); 3476 + if (doff == 0) return js_mkerr(js, "oom"); 3477 + } 3478 + } 3479 + dense_set_length(js, doff, new_len_val); 3480 + return v; 3481 + } 3379 3482 } 3380 3483 3381 3484 if (is_proxy(js, obj)) { ··· 3439 3542 3440 3543 saveval(js, existing + sizeof(jsoff_t) * 2, v); 3441 3544 if (vtype(obj) != T_ARR || klen == 0 || key[0] < '0' || key[0] > '9') goto done_update; 3545 + { jsoff_t doff = get_dense_buf(js, obj); if (doff) goto done_update; } 3442 3546 3443 3547 char *endptr; 3444 3548 unsigned long update_idx = strtoul(key, &endptr, 10); ··· 3482 3586 unsigned long idx = 0; 3483 3587 3484 3588 if (vtype(obj) == T_ARR && klen > 0 && key[0] >= '0' && key[0] <= '9') { 3589 + jsoff_t doff = get_dense_buf(js, obj); 3590 + if (doff) { 3591 + char *inner_endptr; 3592 + idx = strtoul(key, &inner_endptr, 10); 3593 + if (inner_endptr == key + klen) { 3594 + arr_set(js, obj, (jsoff_t)idx, v); return v; 3595 + } 3596 + } 3485 3597 char *inner_endptr; 3486 3598 idx = strtoul(key, &inner_endptr, 10); 3487 3599 if (inner_endptr == key + klen) { ··· 3496 3608 } 3497 3609 3498 3610 jsval_t result = mkprop(js, obj, k, v, 0); 3499 - 3500 3611 if (need_length_update) { 3501 3612 jsoff_t inner_len_off = lkp_interned(js, obj, INTERN_LENGTH, 6); 3502 3613 jsval_t inner_len_key = js_mkstr(js, "length", 6); ··· 5115 5226 int bound_argc = 0; 5116 5227 5117 5228 if (vtype(bound_arr) == T_ARR) { 5118 - jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 5119 - if (len_off != 0) { 5120 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 5121 - if (vtype(len_val) == T_NUM) bound_argc = (int) tod(len_val); 5122 - } 5123 - } 5124 - 5125 - if (bound_argc <= 0) return NULL; 5229 + bound_argc = (int)get_array_length(js, bound_arr); 5230 + } if (bound_argc <= 0) return NULL; 5126 5231 5127 5232 *out_nargs = bound_argc + nargs; 5128 5233 jsval_t *combined = (jsval_t *)ant_calloc(sizeof(jsval_t) * (*out_nargs)); 5129 5234 if (!combined) return NULL; 5130 5235 5131 - for (int i = 0; i < bound_argc; i++) { 5132 - char idx[16]; 5133 - snprintf(idx, sizeof(idx), "%d", i); 5134 - jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 5135 - combined[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 5136 - } 5236 + for (int i = 0; i < bound_argc; i++) combined[i] = arr_get(js, bound_arr, (jsoff_t)i); 5137 5237 for (int i = 0; i < nargs; i++) combined[bound_argc + i] = args[i]; 5138 5238 5139 5239 return combined; ··· 5512 5612 5513 5613 static inline jsval_t resolve_array_length(struct js *js, jsoff_t obj_off) { 5514 5614 jsval_t arr = mkval(T_ARR, obj_off); 5615 + jsoff_t doff = get_dense_buf(js, arr); 5616 + if (doff) return tov(D(dense_length(js, doff))); 5515 5617 return tov(D(get_array_length(js, arr))); 5516 5618 } 5517 5619 5518 5620 static inline jsval_t resolve_array_index_prop(struct js *js, jsoff_t obj_off, const char *key_str, jsoff_t len) { 5519 5621 jsval_t arr = mkval(T_ARR, obj_off); 5622 + jsoff_t doff = get_dense_buf(js, arr); 5623 + if (doff) { 5624 + unsigned long idx = 0; 5625 + for (jsoff_t i = 0; i < len; i++) idx = idx * 10 + (key_str[i] - '0'); 5626 + jsoff_t dlen = dense_length(js, doff); 5627 + if (idx < dlen) { 5628 + jsval_t v = dense_get(js, doff, (jsoff_t)idx); 5629 + if (!is_empty_slot(v)) return v; 5630 + } return js_mkundef(); 5631 + } 5520 5632 jsoff_t prop_off = lkp(js, arr, key_str, len); 5521 5633 if (prop_off != 0) return resolveprop(js, mkval(T_PROP, prop_off)); 5522 5634 return js_mkundef(); ··· 5666 5778 } 5667 5779 5668 5780 if (!is_numeric || (key_len > 1 && key_str[0] == '0')) return js_mkundef(); 5781 + jsoff_t doff = get_dense_buf(js, obj); 5782 + 5783 + if (doff) { arr_set(js, obj, (jsoff_t)idx, val); return val; } 5669 5784 int known_new = 0; jsoff_t tail = loadoff(js, obj_off + sizeof(jsoff_t) * 2); 5670 5785 5671 5786 if (tail != 0 && tail < js->brk) { ··· 5956 6071 return tov(D(utf16_strlen(str_data, byte_len))); 5957 6072 } 5958 6073 if (vtype(obj) == T_ARR) { 5959 - jsoff_t len_off = lkp(js, obj, "length", 6); 5960 - if (len_off != 0) { 5961 - return mkval(T_PROP, len_off); 5962 - } 5963 6074 jsval_t key = js_mkstr(js, "length", 6); 5964 - jsval_t len_val = tov(D(js_arr_len(js, obj))); 5965 - jsval_t prop = js_setprop(js, obj, key, len_val); 5966 - return prop; 6075 + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 5967 6076 } 5968 6077 } 5969 6078 if (vtype(obj) == T_STR) { ··· 6006 6115 jsval_t func_obj = mkval(T_OBJ, vdata(obj)); 6007 6116 jsoff_t off = lkp_proto(js, obj, keystr, keylen); 6008 6117 if (off != 0) { 6009 - if (desc) { 6010 - jsval_t key = js_mkstr(js, keystr, keylen); 6011 - return mkpropref(obj_off, (jsoff_t)vdata(key)); 6012 - } 6013 - return mkval(T_PROP, off); 6118 + jsval_t key = js_mkstr(js, keystr, keylen); 6119 + return mkpropref(obj_off, (jsoff_t)vdata(key)); 6014 6120 } 6015 6121 if (streq(keystr, keylen, "name", 4)) return js_mkstr(js, "", 0); 6016 6122 jsval_t key = js_mkstr(js, keystr, keylen); ··· 6065 6171 } 6066 6172 6067 6173 if (prop_off != 0) { 6068 - return mkval(T_PROP, prop_off); 6174 + jsval_t key = js_mkstr(js, keystr, keylen); 6175 + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 6069 6176 } 6070 6177 6071 6178 jsval_t dyn_result = try_dynamic_getter(js, obj, keystr, keylen); ··· 6074 6181 return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 6075 6182 } 6076 6183 6077 - jsoff_t off = lkp_proto(js, obj, keystr, keylen); 6078 - if (off == 0) { 6079 - jsval_t key = js_mkstr(js, keystr, keylen); 6080 - return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 6081 - } 6082 - return mkval(T_PROP, off); 6184 + jsval_t key = js_mkstr(js, keystr, keylen); 6185 + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 6083 6186 } 6084 6187 6085 6188 static jsval_t do_dot_op(struct js *js, jsval_t l, jsval_t r) { ··· 6143 6246 jsval_t func_obj = mkval(T_OBJ, vdata(l)); 6144 6247 jsoff_t off = lkp_proto(js, l, ptr, plen); 6145 6248 if (off != 0) { 6146 - if (desc) { 6147 - jsval_t key = js_mkstr(js, ptr, plen); 6148 - return mkpropref(obj_off, (jsoff_t)vdata(key)); 6149 - } 6150 - return mkval(T_PROP, off); 6249 + jsval_t key = js_mkstr(js, ptr, plen); 6250 + return mkpropref(obj_off, (jsoff_t)vdata(key)); 6151 6251 } 6152 6252 if (streq(ptr, plen, "name", 4)) return js_mkstr(js, "", 0); 6153 6253 jsval_t key = js_mkstr(js, ptr, plen); ··· 6228 6328 6229 6329 jsoff_t own_off = lkp(js, l, ptr, plen); 6230 6330 if (own_off != 0) { 6231 - jsoff_t obj_off = (jsoff_t)vdata(l); 6232 - descriptor_entry_t *desc = lookup_descriptor(obj_off, ptr, plen); 6233 - if (desc) { 6234 - jsval_t key = js_mkstr(js, ptr, plen); 6235 - return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 6236 - } 6237 - return mkval(T_PROP, own_off); 6331 + jsval_t key = js_mkstr(js, ptr, plen); 6332 + return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 6238 6333 } 6239 6334 6240 6335 jsval_t result = try_dynamic_getter(js, l, ptr, plen); 6241 6336 if (vtype(result) != T_UNDEF) { 6242 6337 own_off = lkp(js, l, ptr, plen); 6243 - if (own_off != 0) return mkval(T_PROP, own_off); 6338 + if (own_off != 0) { 6339 + jsval_t key = js_mkstr(js, ptr, plen); 6340 + return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 6341 + } 6244 6342 } 6245 6343 6246 6344 jsval_t key = js_mkstr(js, ptr, plen); ··· 6758 6856 jsval_t rest_array = mkarr(js); 6759 6857 if (!is_err(rest_array)) { 6760 6858 jsoff_t idx = 0; 6761 - while (argi < argc) { 6762 - jsval_t key; 6763 - if (idx < 10 && INTERN_IDX[idx]) { 6764 - key = js_mkstr(js, INTERN_IDX[idx], 1); 6765 - } else { 6766 - char idxstr[16]; 6767 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 6768 - key = js_mkstr(js, idxstr, idxlen); 6769 - } 6770 - js_setprop(js, rest_array, key, args[argi++]); 6771 - idx++; 6772 - } 6773 - jsval_t len_key = js_mkstr(js, "length", 6); 6774 - js_setprop(js, rest_array, len_key, tov((double) idx)); 6859 + while (argi < argc) { arr_set(js, rest_array, idx, args[argi++]); idx++; } 6775 6860 rest_array = mkval(T_ARR, vdata(rest_array)); 6776 6861 js_setprop(js, function_scope, js_mkstr(js, &fn[pf->rest_param_start], pf->rest_param_len), rest_array); 6777 6862 } ··· 6869 6954 6870 6955 jsval_t bound_arr = get_slot(js, func_obj, SLOT_BOUND_ARGS); 6871 6956 if (vtype(bound_arr) == T_ARR) { 6872 - jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 6873 - if (len_off != 0) { 6874 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 6875 - if (vtype(len_val) == T_NUM) { 6876 - bound_argc = (int) tod(len_val); 6877 - } 6878 - } 6957 + bound_argc = (int) get_array_length(js, bound_arr); 6879 6958 6880 6959 if (bound_argc > 0) { 6881 6960 combined_nargs = bound_argc + nargs; 6882 6961 combined_args = (jsval_t *)ant_calloc(sizeof(jsval_t) * combined_nargs); 6883 6962 if (combined_args) { 6884 - for (int i = 0; i < bound_argc; i++) { 6885 - char idx[16]; 6886 - snprintf(idx, sizeof(idx), "%d", i); 6887 - jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 6888 - combined_args[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 6889 - } 6890 - for (int i = 0; i < nargs; i++) { 6891 - combined_args[bound_argc + i] = args[i]; 6892 - } 6893 - args = combined_args; 6894 - nargs = combined_nargs; 6963 + for (int i = 0; i < bound_argc; i++) combined_args[i] = arr_get(js, bound_arr, (jsoff_t)i); 6964 + for (int i = 0; i < nargs; i++) combined_args[bound_argc + i] = args[i]; 6965 + args = combined_args; nargs = combined_nargs; 6895 6966 } 6896 6967 } 6897 6968 } ··· 7051 7122 if (!is_err(rest_array)) { 7052 7123 jsoff_t idx = 0; 7053 7124 while (arg_idx < nargs) { 7054 - char idxstr[16]; 7055 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 7056 - jsval_t key = js_mkstr(js, idxstr, idxlen); 7057 - js_setprop(js, rest_array, key, args[arg_idx]); 7058 - idx++; 7059 - arg_idx++; 7125 + arr_set(js, rest_array, idx, args[arg_idx]); 7126 + idx++; arg_idx++; 7060 7127 } 7061 - jsval_t len_key = js_mkstr(js, "length", 6); 7062 - js_setprop(js, rest_array, len_key, tov((double) idx)); 7063 7128 rest_array = mkval(T_ARR, vdata(rest_array)); 7064 7129 js_setprop(js, function_scope, js_mkstr(js, &fn[rest_param_start], rest_param_len), rest_array); 7065 7130 } ··· 7980 8045 7981 8046 jsval_t strings_arr = mkarr(js); 7982 8047 for (int i = 0; i < string_count; i++) { 7983 - char idx[16]; 7984 - snprintf(idx, sizeof(idx), "%d", i); 7985 - js_setprop(js, strings_arr, js_mkstr(js, idx, strlen(idx)), strings[i]); 8048 + arr_set(js, strings_arr, (jsoff_t)i, strings[i]); 7986 8049 } 7987 - js_setprop(js, strings_arr, js_mkstr(js, "length", 6), tov((double)string_count)); 7988 - strings_arr = mkval(T_ARR, vdata(strings_arr)); 7989 8050 7990 8051 jsval_t args[65]; 7991 8052 args[0] = strings_arr; ··· 8286 8347 8287 8348 js->consumed = 1; 8288 8349 jsoff_t idx = 0; 8350 + 8289 8351 while (next(js) != TOK_RBRACKET) { 8290 8352 if (next(js) == TOK_COMMA) { 8291 - idx++; 8292 - js->consumed = 1; 8353 + if (exe) { 8354 + jsoff_t doff = get_dense_buf(js, arr); 8355 + if (doff && idx >= dense_capacity(js, doff)) doff = dense_grow(js, arr, idx + 1); 8356 + if (doff) { 8357 + dense_set(js, doff, idx, T_EMPTY); 8358 + if (idx >= dense_length(js, doff)) dense_set_length(js, doff, idx + 1); 8359 + } 8360 + } 8361 + idx++; js->consumed = 1; 8293 8362 continue; 8294 8363 } 8295 8364 ··· 8302 8371 8303 8372 jsval_t resolved = resolveprop(js, val); 8304 8373 if (!is_spread) { 8305 - char idxstr[16]; 8306 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 8307 - jsval_t res = js_mkprop_fast(js, arr, idxstr, idxlen, resolved); 8308 - if (is_err(res)) return res; 8374 + arr_set(js, arr, idx, resolved); 8309 8375 idx++; goto next_elem; 8310 8376 } 8311 8377 ··· 8315 8381 if (t == T_STR) { 8316 8382 jsoff_t slen, soff = vstr(js, resolved, &slen); 8317 8383 for (jsoff_t i = 0; i < slen; i++) { 8318 - char idxstr[16]; 8319 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 8320 8384 jsval_t ch = js_mkstr(js, (char *)&js->mem[soff + i], 1); 8321 - js_mkprop_fast(js, arr, idxstr, idxlen, ch); 8322 - idx++; 8385 + arr_set(js, arr, idx, ch); idx++; 8323 8386 } 8324 8387 goto next_elem; 8325 8388 } 8326 8389 8327 8390 jsoff_t len = js_arr_len(js, resolved); 8328 8391 for (jsoff_t i = 0; i < len; i++) { 8329 - char src_idx[16], dst_idx[16]; 8330 - size_t src_len = uint_to_str(src_idx, sizeof(src_idx), (unsigned)i); 8331 - size_t dst_len = uint_to_str(dst_idx, sizeof(dst_idx), (unsigned)idx); 8332 - jsoff_t prop_off = lkp(js, resolved, src_idx, src_len); 8333 - jsval_t elem = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 8334 - js_mkprop_fast(js, arr, dst_idx, dst_len, elem); 8335 - idx++; 8392 + jsval_t elem = arr_get(js, resolved, i); 8393 + arr_set(js, arr, idx, elem); idx++; 8336 8394 } 8337 8395 8338 8396 next_elem: ··· 8342 8400 8343 8401 EXPECT(TOK_RBRACKET); 8344 8402 if (exe) { 8345 - jsval_t res = js_mkprop_fast(js, arr, "length", 6, tov((double)idx)); 8346 - if (is_err(res)) return res; 8403 + jsoff_t doff = get_dense_buf(js, arr); 8404 + if (doff) dense_set_length(js, doff, idx); else { 8405 + jsval_t res = js_mkprop_fast(js, arr, "length", 6, tov((double)idx)); 8406 + if (is_err(res)) return res; 8407 + } 8347 8408 arr = mkval(T_ARR, vdata(arr)); 8348 8409 } 8349 8410 return arr; ··· 9605 9666 jsval_t err = check_frozen_sealed(js, obj, "delete"); 9606 9667 if (vtype(err) != T_UNDEF) return err; 9607 9668 9669 + { 9670 + jsoff_t header = loadoff(js, obj_off); 9671 + if ((header & 3) == T_OBJ && (header & ARRMASK)) { 9672 + jsval_t arr_val = mkval(T_ARR, (uint64_t)obj_off); 9673 + jsoff_t doff = get_dense_buf(js, arr_val); 9674 + if (doff) { 9675 + unsigned long del_idx; 9676 + if (parse_array_index(key_str, len, dense_length(js, doff), &del_idx)) { 9677 + arr_del(js, arr_val, (jsoff_t)del_idx); 9678 + return js_true; 9679 + } 9680 + } 9681 + } 9682 + } 9683 + 9608 9684 jsoff_t prop_off = lkp(js, obj, key_str, len); 9609 9685 if (prop_off == 0) { 9610 9686 try_dynamic_deleter(js, obj, key_str, len); ··· 9638 9714 return js_true; 9639 9715 } 9640 9716 9641 - if (vtype(operand) != T_PROP) return js_true; 9642 - 9643 - jsoff_t prop_off = (jsoff_t)vdata(operand); 9644 - if (is_nonconfig_prop(js, prop_off)) { 9645 - if (js->flags & F_STRICT) return js_mkerr(js, "cannot delete non-configurable property"); 9646 - return js_false; 9647 - } 9648 - 9649 - jsoff_t owner_obj_off = 0, prev_prop_off = 0; 9650 - bool is_first_prop = false; 9651 - for (jsoff_t off = 0; off < js->brk; ) { 9652 - jsoff_t v = loadoff(js, off); 9653 - jsoff_t cleaned = v & ~FLAGMASK; 9654 - jsoff_t n = esize(cleaned); 9655 - if ((cleaned & 3) == T_OBJ) { 9656 - jsoff_t first_prop = cleaned & ~3ULL; 9657 - if (first_prop == prop_off) { owner_obj_off = off; is_first_prop = true; break; } 9658 - for (jsoff_t cur = first_prop; cur != 0 && cur < js->brk; ) { 9659 - jsoff_t nx = loadoff(js, cur) & ~(3U | FLAGMASK); 9660 - if (nx == prop_off) { owner_obj_off = off; prev_prop_off = cur; break; } 9661 - cur = nx; 9662 - } 9663 - if (owner_obj_off) break; 9664 - } 9665 - off += n; 9666 - } 9667 - 9668 - if (owner_obj_off) { 9669 - jsval_t owner_obj = mkval(T_OBJ, owner_obj_off); 9670 - jsval_t err = check_frozen_sealed(js, owner_obj, "delete"); 9671 - if (vtype(err) != T_UNDEF) return err; 9672 - 9673 - jsoff_t key_str_off = loadoff(js, (jsoff_t)(prop_off + sizeof(jsoff_t))); 9674 - jsoff_t key_len = (loadoff(js, key_str_off) >> 3) - 1; 9675 - const char *key_str = (char *)&js->mem[key_str_off + sizeof(jsoff_t)]; 9676 - descriptor_entry_t *desc = lookup_descriptor(owner_obj_off, key_str, key_len); 9677 - if (desc && !desc->configurable) { 9678 - if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "cannot delete non-configurable property"); 9679 - return js_false; 9680 - } 9681 - unlink_prop(js, owner_obj_off, prop_off, is_first_prop ? 0 : prev_prop_off); 9682 - } 9683 9717 return js_true; 9684 9718 } 9685 9719 ··· 10872 10906 10873 10907 jshdl_t h_obj = js_root(js, iter_obj); 10874 10908 const char *tag_sym_key = get_toStringTag_sym_key(); 10909 + 10875 10910 size_t tag_sym_len = tag_sym_key ? strlen(tag_sym_key) : 0; 10911 + char key_buf[256]; 10912 + 10913 + if (obj_type == T_ARR) { 10914 + jsval_t cur_obj = js_deref(js, h_obj); 10915 + jsoff_t doff = get_dense_buf(js, cur_obj); 10916 + if (doff) { 10917 + jsoff_t dense_len = dense_length(js, doff); 10918 + for (jsoff_t i = 0; i < dense_len; i++) { 10919 + jsval_t v = dense_get(js, doff, i); 10920 + if (is_empty_slot(v)) continue; 10921 + size_t klen = uint_to_str(key_buf, sizeof(key_buf), (unsigned)i); 10922 + jsval_t out; 10923 + int rc = for_iter_step(js, ctx, js_mkstr(js, key_buf, (jsoff_t)klen), &out); 10924 + if (rc) { js_unroot(js, h_obj); return (rc == 2) ? out : js_mkundef(); } 10925 + } 10926 + } 10927 + } 10876 10928 10877 10929 jsoff_t prop_idx = 0; 10878 - char key_buf[256]; 10879 10930 10880 10931 for (;;) { 10881 10932 jsval_t cur_obj = js_deref(js, h_obj); ··· 10898 10949 10899 10950 bool skip = streq(key, klen, STR_PROTO, STR_PROTO_LEN); 10900 10951 if (!skip && tag_sym_key) skip = streq(key, klen, tag_sym_key, tag_sym_len); 10952 + if (!skip && is_array_index(key, klen)) skip = true; 10901 10953 10902 10954 if (!skip) { 10903 10955 descriptor_entry_t *desc = lookup_descriptor(cur_obj_off, key, klen); ··· 10926 10978 10927 10979 jsoff_t length = 0; { 10928 10980 jsval_t arr = js_deref(js, h_iterable); 10929 - jsoff_t next_prop_off = loadoff(js, (jsoff_t) vdata(arr)) & ~(3U | FLAGMASK); 10930 - jsoff_t scan = next_prop_off; 10931 - while (scan < js->brk && scan != 0) { 10932 - jsoff_t header = loadoff(js, scan); 10933 - if (is_slot_prop(header)) { scan = next_prop(header); continue; } 10934 - const char *key; jsoff_t klen; 10935 - get_prop_key(js, scan, &key, &klen); 10936 - if (streq(key, klen, "length", 6)) { 10937 - jsval_t val = get_prop_val(js, scan); 10938 - if (vtype(val) == T_NUM) length = (jsoff_t) tod(val); 10939 - break; 10940 - } 10941 - scan = next_prop(header); 10942 - } 10981 + length = get_array_length(js, arr); 10943 10982 } 10944 10983 10945 10984 for (jsoff_t i = 0; i < length; i++) { 10946 10985 jsval_t arr = js_deref(js, h_iterable); 10947 - jsoff_t next_prop_off = loadoff(js, (jsoff_t) vdata(arr)) & ~(3U | FLAGMASK); 10948 - 10949 - char idx[16]; 10950 - snprintf(idx, sizeof(idx), "%u", (unsigned) i); 10951 - jsoff_t idxlen = (jsoff_t) strlen(idx); 10952 - jsoff_t prop = next_prop_off; 10953 - jsval_t val = js_mkundef(); 10954 - 10955 - while (prop < js->brk && prop != 0) { 10956 - jsoff_t header = loadoff(js, prop); 10957 - if (is_slot_prop(header)) { prop = next_prop(header); continue; } 10958 - const char *key; jsoff_t klen; 10959 - get_prop_key(js, prop, &key, &klen); 10960 - if (streq(key, klen, idx, idxlen)) { val = get_prop_val(js, prop); break; } 10961 - prop = next_prop(header); 10962 - } 10986 + jsval_t val = arr_get(js, arr, i); 10963 10987 10964 10988 jsval_t err = for_iter_bind_var(js, ctx, val); 10965 10989 if (is_err(err)) { js_unroot(js, h_iterable); return err; } ··· 13351 13375 } 13352 13376 13353 13377 static int extract_array_args(struct js *js, jsval_t arr, jsval_t **out_args) { 13354 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 13355 - if (len_off == 0) return 0; 13356 - 13357 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 13358 - if (vtype(len_val) != T_NUM) return 0; 13359 - 13360 - int len = (int) tod(len_val); 13378 + int len = (int) get_array_length(js, arr); 13361 13379 if (len <= 0) return 0; 13362 13380 13363 13381 jsval_t *args_out = (jsval_t *)ant_calloc(sizeof(jsval_t) * len); 13364 13382 if (!args_out) return 0; 13365 13383 13366 13384 for (int i = 0; i < len; i++) { 13367 - char idx[16]; 13368 - snprintf(idx, sizeof(idx), "%d", i); 13369 - jsoff_t prop_off = lkp(js, arr, idx, strlen(idx)); 13370 - args_out[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 13385 + args_out[i] = arr_get(js, arr, (jsoff_t)i); 13371 13386 } 13372 13387 13373 13388 *out_args = args_out; ··· 13517 13532 13518 13533 if (bound_argc > 0) { 13519 13534 jsval_t bound_arr = mkarr(js); 13520 - for (int i = 0; i < bound_argc; i++) { 13521 - char idx[16]; 13522 - snprintf(idx, sizeof(idx), "%d", i); 13523 - js_setprop(js, bound_arr, js_mkstr(js, idx, strlen(idx)), bound_args[i]); 13524 - } 13525 - js_setprop(js, bound_arr, js_mkstr(js, "length", 6), tov((double) bound_argc)); 13535 + for (int i = 0; i < bound_argc; i++) arr_set(js, bound_arr, (jsoff_t)i, bound_args[i]); 13526 13536 set_slot(js, bound_func, SLOT_BOUND_ARGS, bound_arr); 13527 13537 } 13528 13538 ··· 13578 13588 13579 13589 if (bound_argc > 0) { 13580 13590 jsval_t bound_arr = mkarr(js); 13581 - for (int i = 0; i < bound_argc; i++) { 13582 - char idx[16]; 13583 - snprintf(idx, sizeof(idx), "%d", i); 13584 - js_setprop(js, bound_arr, js_mkstr(js, idx, strlen(idx)), bound_args[i]); 13585 - } 13586 - js_setprop(js, bound_arr, js_mkstr(js, "length", 6), tov((double) bound_argc)); 13591 + for (int i = 0; i < bound_argc; i++) arr_set(js, bound_arr, (jsoff_t)i, bound_args[i]); 13587 13592 set_slot(js, bound_func, SLOT_BOUND_ARGS, bound_arr); 13588 13593 } 13589 13594 ··· 13602 13607 if (nargs == 1 && vtype(args[0]) == T_NUM) { 13603 13608 jsval_t err = validate_array_length(js, args[0]); 13604 13609 if (is_err(err)) return err; 13605 - js_setprop(js, arr, ANT_STRING("length"), tov(tod(args[0]))); 13606 - } else if (nargs > 0) { 13607 - for (int i = 0; i < nargs; i++) { 13608 - char idxstr[16]; 13609 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 13610 - js_setprop(js, arr, js_mkstr(js, idxstr, idxlen), args[i]); 13610 + jsoff_t new_len = (jsoff_t)tod(args[0]); 13611 + jsoff_t doff = get_dense_buf(js, arr); 13612 + if (doff) { 13613 + if (new_len > dense_capacity(js, doff)) doff = dense_grow(js, arr, new_len); 13614 + if (doff) dense_set_length(js, doff, new_len); 13611 13615 } 13612 - js_setprop(js, arr, ANT_STRING("length"), tov((double)nargs)); 13616 + } else if (nargs > 0) { 13617 + for (int i = 0; i < nargs; i++) arr_set(js, arr, (jsoff_t)i, args[i]); 13613 13618 } 13614 13619 13615 13620 return arr; ··· 14960 14965 jsoff_t len = get_array_length(js, keys_arr); 14961 14966 14962 14967 for (jsoff_t i = 0; i < len; i++) { 14963 - char idx_buf[16]; 14964 - size_t idx_len = uint_to_str(idx_buf, sizeof(idx_buf), (unsigned)i); 14965 - jsoff_t prop_off = lkp(js, keys_arr, idx_buf, idx_len); 14966 - if (!prop_off) continue; 14967 - jsval_t key_val = resolveprop(js, mkval(T_PROP, prop_off)); 14968 + jsval_t key_val = arr_get(js, keys_arr, i); 14968 14969 if (vtype(key_val) != T_STR) continue; 14969 14970 jsoff_t klen; jsoff_t str_off = vstr(js, key_val, &klen); 14970 14971 const char *key = (const char *)&js->mem[str_off]; ··· 15009 15010 jsval_t obj = args[0]; 15010 15011 15011 15012 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 15013 + bool is_arr = (vtype(obj) == T_ARR); 15012 15014 if (vtype(obj) == T_FUNC) obj = mkval(T_OBJ, vdata(obj)); 15013 15015 15014 15016 jsoff_t obj_off = (jsoff_t)vdata(obj); ··· 15018 15020 15019 15021 jsval_t arr = mkarr(js); 15020 15022 jsoff_t idx = 0; 15023 + 15024 + if (is_arr) { 15025 + jsval_t arr_val = mkval(T_ARR, (uint64_t)obj_off); 15026 + jsoff_t doff = get_dense_buf(js, arr_val); 15027 + if (doff) { 15028 + jsoff_t dense_len = dense_length(js, doff); 15029 + for (jsoff_t i = 0; i < dense_len; i++) { 15030 + jsval_t v = dense_get(js, doff, i); 15031 + if (is_empty_slot(v)) continue; 15032 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 15033 + jsval_t key_val = js_mkstr(js, idxstr, idxlen); 15034 + arr_set(js, arr, idx, key_val); 15035 + idx++; 15036 + } 15037 + } 15038 + } 15039 + 15021 15040 jsoff_t next = loadoff(js, obj_off) & ~(3U | FLAGMASK); 15022 15041 15023 15042 while (next < js->brk && next != 0) { ··· 15030 15049 15031 15050 next = next_prop(header); 15032 15051 if (is_internal_prop(key, klen)) continue; 15052 + if (is_arr && is_array_index(key, klen)) continue; 15033 15053 15034 15054 bool should_include = true; 15035 15055 descriptor_entry_t *desc = lookup_descriptor(obj_off, key, klen); 15036 15056 if (desc) should_include = desc->enumerable; 15037 15057 15038 15058 if (should_include) { 15039 - char idxstr[16]; 15040 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 15041 15059 jsval_t key_val = js_mkstr(js, key, klen); 15042 - js_mkprop_fast(js, arr, idxstr, idxlen, key_val); 15060 + arr_set(js, arr, idx, key_val); 15043 15061 idx++; 15044 15062 } 15045 15063 } ··· 15050 15068 if (!desc->enumerable) continue; 15051 15069 if (!desc->has_getter && !desc->has_setter) continue; 15052 15070 15053 - char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 15054 15071 jsval_t key_val = js_mkstr(js, desc->prop_name, desc->prop_len); 15055 - js_mkprop_fast(js, arr, idxstr, idxlen, key_val); idx++; 15072 + arr_set(js, arr, idx, key_val); 15073 + idx++; 15056 15074 } 15057 - 15058 - jsval_t len_val = tov((double) idx); 15059 - js_mkprop_fast(js, arr, "length", 6, len_val); 15060 15075 15061 15076 return mkval(T_ARR, vdata(arr)); 15062 15077 } ··· 15066 15081 jsval_t obj = args[0]; 15067 15082 15068 15083 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 15084 + bool is_arr = (vtype(obj) == T_ARR); 15069 15085 if (vtype(obj) == T_FUNC) obj = mkval(T_OBJ, vdata(obj)); 15070 15086 15071 15087 jsoff_t obj_off = (jsoff_t)vdata(obj); ··· 15074 15090 if (acc && acc->keys && acc->getter) return iterate_dynamic_keys(js, obj, acc, NULL); 15075 15091 15076 15092 jsval_t arr = mkarr(js); jsoff_t idx = 0; 15093 + 15094 + if (is_arr) { 15095 + jsval_t arr_val = mkval(T_ARR, (uint64_t)obj_off); 15096 + jsoff_t doff = get_dense_buf(js, arr_val); 15097 + if (doff) { 15098 + jsoff_t dense_len = dense_length(js, doff); 15099 + for (jsoff_t i = 0; i < dense_len; i++) { 15100 + jsval_t v = dense_get(js, doff, i); 15101 + if (is_empty_slot(v)) continue; 15102 + arr_set(js, arr, idx, v); 15103 + idx++; 15104 + } 15105 + } 15106 + } 15107 + 15077 15108 jsoff_t next = loadoff(js, obj_off) & ~(3U | FLAGMASK); 15078 15109 15079 15110 while (next < js->brk && next != 0) { ··· 15087 15118 15088 15119 next = next_prop(header); 15089 15120 if (is_internal_prop(key, klen)) continue; 15121 + if (is_arr && is_array_index(key, klen)) continue; 15090 15122 15091 15123 bool should_include = true; 15092 15124 descriptor_entry_t *desc = lookup_descriptor(obj_off, key, klen); 15093 15125 if (desc) should_include = desc->enumerable; 15094 15126 15095 15127 if (should_include) { 15096 - char idxstr[16]; 15097 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 15098 - js_mkprop_fast(js, arr, idxstr, idxlen, val); 15128 + arr_set(js, arr, idx, val); 15099 15129 idx++; 15100 15130 } 15101 15131 } 15102 15132 15103 - jsval_t len_val = tov((double) idx); 15104 - js_mkprop_fast(js, arr, "length", 6, len_val); 15105 - 15106 15133 return mkval(T_ARR, vdata(arr)); 15107 15134 } 15108 15135 15109 15136 static jsval_t map_to_entry(struct js *js, jsval_t key, jsval_t val) { 15110 15137 jsval_t pair = mkarr(js); 15111 - js_mkprop_fast(js, pair, "0", 1, key); 15112 - js_mkprop_fast(js, pair, "1", 1, val); 15113 - js_mkprop_fast(js, pair, "length", 6, tov(2.0)); 15138 + arr_set(js, pair, 0, key); 15139 + arr_set(js, pair, 1, val); 15114 15140 return mkval(T_ARR, vdata(pair)); 15115 15141 } 15116 15142 ··· 15119 15145 jsval_t obj = args[0]; 15120 15146 15121 15147 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 15148 + bool is_arr_obj = (vtype(obj) == T_ARR); 15122 15149 if (vtype(obj) == T_FUNC) obj = mkval(T_OBJ, vdata(obj)); 15123 15150 15124 15151 jsoff_t obj_off = (jsoff_t)vdata(obj); ··· 15130 15157 15131 15158 jsval_t arr = mkarr(js); 15132 15159 jsoff_t idx = 0; 15160 + 15161 + if (is_arr_obj) { 15162 + jsval_t arr_val = mkval(T_ARR, (uint64_t)obj_off); 15163 + jsoff_t doff = get_dense_buf(js, arr_val); 15164 + if (doff) { 15165 + jsoff_t dense_len = dense_length(js, doff); 15166 + for (jsoff_t i = 0; i < dense_len; i++) { 15167 + jsval_t v = dense_get(js, doff, i); 15168 + if (is_empty_slot(v)) continue; 15169 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 15170 + jsval_t pair = mkarr(js); 15171 + arr_set(js, pair, 0, js_mkstr(js, idxstr, idxlen)); 15172 + arr_set(js, pair, 1, v); 15173 + arr_set(js, arr, idx, mkval(T_ARR, vdata(pair))); 15174 + idx++; 15175 + } 15176 + } 15177 + } 15178 + 15133 15179 jsoff_t next = loadoff(js, obj_off) & ~(3U | FLAGMASK); 15134 15180 15135 15181 while (next < js->brk && next != 0) { ··· 15143 15189 15144 15190 next = next_prop(header); 15145 15191 if (is_internal_prop(key, klen)) continue; 15192 + if (is_arr_obj && is_array_index(key, klen)) continue; 15146 15193 15147 15194 bool should_include = true; 15148 15195 descriptor_entry_t *desc = lookup_descriptor(obj_off, key, klen); ··· 15151 15198 if (should_include) { 15152 15199 jsval_t pair = mkarr(js); 15153 15200 jsval_t key_val = js_mkstr(js, key, klen); 15154 - js_mkprop_fast(js, pair, "0", 1, key_val); 15155 - js_mkprop_fast(js, pair, "1", 1, val); 15156 - js_mkprop_fast(js, pair, "length", 6, tov(2.0)); 15157 - 15158 - char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 15159 - js_mkprop_fast(js, arr, idxstr, idxlen, mkval(T_ARR, vdata(pair))); idx++; 15201 + arr_set(js, pair, 0, key_val); 15202 + arr_set(js, pair, 1, val); 15203 + arr_set(js, arr, idx, mkval(T_ARR, vdata(pair))); 15204 + idx++; 15160 15205 } 15161 15206 } 15162 - 15163 - jsval_t len_val = tov((double) idx); 15164 - js_mkprop_fast(js, arr, "length", 6, len_val); 15165 15207 15166 15208 return mkval(T_ARR, vdata(arr)); 15167 15209 } ··· 15688 15730 } 15689 15731 15690 15732 jsval_t result = js_mkobj(js); 15691 - jsoff_t len_off = lkp_interned(js, iterable, INTERN_LENGTH, 6); 15692 - if (len_off == 0) return result; 15693 - 15694 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 15695 - if (vtype(len_val) != T_NUM) return result; 15696 - 15697 - jsoff_t len = (jsoff_t) tod(len_val); 15733 + jsoff_t len = get_array_length(js, iterable); 15734 + if (len == 0) return result; 15698 15735 15699 15736 for (jsoff_t i = 0; i < len; i++) { 15700 - char idx_str[16]; 15701 - snprintf(idx_str, sizeof(idx_str), "%u", (unsigned) i); 15702 - 15703 - jsoff_t entry_off = lkp(js, iterable, idx_str, strlen(idx_str)); 15704 - if (entry_off == 0) continue; 15705 - 15706 - jsval_t entry = resolveprop(js, mkval(T_PROP, entry_off)); 15737 + jsval_t entry = arr_get(js, iterable, i); 15707 15738 if (vtype(entry) != T_ARR && vtype(entry) != T_OBJ) continue; 15708 15739 15709 - jsoff_t key_off = lkp(js, entry, "0", 1); 15710 - if (key_off == 0) continue; 15711 - jsval_t key = resolveprop(js, mkval(T_PROP, key_off)); 15712 - 15713 - jsoff_t val_off = lkp(js, entry, "1", 1); 15714 - jsval_t val = (val_off != 0) ? resolveprop(js, mkval(T_PROP, val_off)) : js_mkundef(); 15740 + jsval_t key = arr_get(js, entry, 0); 15741 + if (is_undefined(key)) continue; 15742 + jsval_t val = arr_get(js, entry, 1); 15715 15743 15716 15744 if (vtype(key) != T_STR) { 15717 15745 char buf[64]; ··· 15810 15838 next = next_prop(header); 15811 15839 } 15812 15840 15813 - if (count == 0) { 15814 - jsval_t arr = mkarr(js); 15815 - js_mkprop_fast(js, arr, "length", 6, tov(0)); 15816 - return mkval(T_ARR, vdata(arr)); 15817 - } 15818 - 15819 - jsval_t *keys = malloc(count * sizeof(jsval_t)); 15820 - if (!keys) return js_mkerr(js, "out of memory"); 15841 + if (count == 0) return mkarr(js); 15821 15842 15843 + bool is_arr_obj = (vtype(obj) == T_ARR); 15844 + jsval_t arr = mkarr(js); 15822 15845 jsoff_t idx = 0; 15846 + 15847 + if (is_arr_obj) { 15848 + jsval_t arr_val = mkval(T_ARR, (uint64_t)(jsoff_t)vdata(obj)); 15849 + jsoff_t doff = get_dense_buf(js, arr_val); 15850 + if (doff) { 15851 + jsoff_t dense_len = dense_length(js, doff); 15852 + for (jsoff_t i = 0; i < dense_len; i++) { 15853 + jsval_t v = dense_get(js, doff, i); 15854 + if (is_empty_slot(v)) continue; 15855 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 15856 + arr_set(js, arr, idx++, js_mkstr(js, idxstr, idxlen)); 15857 + } 15858 + } 15859 + } 15860 + 15823 15861 next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 15824 - while (next < js->brk && next != 0 && idx < count) { 15862 + while (next < js->brk && next != 0) { 15825 15863 jsoff_t header = loadoff(js, next); 15826 15864 if (!is_slot_prop(header)) { 15827 15865 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 15828 15866 jsoff_t klen = offtolen(loadoff(js, koff)); 15829 15867 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 15830 15868 if (!is_internal_prop(key, klen)) { 15831 - keys[idx++] = js_mkstr(js, key, klen); 15869 + if (is_arr_obj && is_array_index(key, klen)) continue; 15870 + arr_set(js, arr, idx++, js_mkstr(js, key, klen)); 15832 15871 } 15833 15872 } 15834 15873 next = next_prop(header); 15835 15874 } 15836 15875 15837 - jsval_t arr = mkarr(js); 15838 - for (jsoff_t i = 0; i < idx; i++) { 15839 - char idxstr[16]; 15840 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 15841 - js_mkprop_fast(js, arr, idxstr, idxlen, keys[i]); 15842 - } 15876 + if (is_arr_obj) arr_set(js, arr, idx++, js_mkstr(js, "length", 6)); 15843 15877 15844 - free(keys); 15845 - js_mkprop_fast(js, arr, "length", 6, tov((double) idx)); 15846 15878 return mkval(T_ARR, vdata(arr)); 15847 15879 } 15848 15880 ··· 15869 15901 uint64_t sym_id = 0; 15870 15902 for (const char *p = key + 6; *p >= '0' && *p <= '9' && sym_id <= PROPREF_PAYLOAD / 10; p++) 15871 15903 sym_id = sym_id * 10 + (uint64_t)(*p - '0'); 15872 - char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx++); 15873 - js_mkprop_fast(js, arr, idxstr, idxlen, mkval(T_SYMBOL, (sym_id & PROPREF_PAYLOAD) << PROPREF_KEY_SHIFT)); 15904 + arr_set(js, arr, idx++, mkval(T_SYMBOL, (sym_id & PROPREF_PAYLOAD) << PROPREF_KEY_SHIFT)); 15874 15905 } 15875 15906 } 15876 15907 next = next_prop(header); 15877 15908 } 15878 15909 15879 - js_mkprop_fast(js, arr, "length", 6, tov((double)idx)); 15880 15910 return mkval(T_ARR, vdata(arr)); 15881 15911 } 15882 15912 ··· 16067 16097 jsval_t result = mkarr(js); 16068 16098 if (is_err(result)) return result; 16069 16099 16100 + jsoff_t doff = get_dense_buf(js, arr); 16101 + if (doff) { 16102 + for (jsoff_t i = 0; i < len; i++) { 16103 + jsval_t v = dense_get(js, doff, i); 16104 + arr_set(js, result, i, v); 16105 + } 16106 + return result; 16107 + } 16108 + 16070 16109 ant_iter_t iter = js_prop_iter_begin(js, arr); 16071 16110 const char *key; 16072 16111 size_t key_len; ··· 16110 16149 return len_val; 16111 16150 } 16112 16151 16113 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16114 - jsoff_t len = 0; 16152 + jsoff_t len = get_array_length(js, arr); 16115 16153 16116 - if (off != 0) { 16117 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16118 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16154 + jsoff_t doff = get_dense_buf(js, arr); 16155 + if (doff) { 16156 + for (int i = 0; i < nargs; i++) { 16157 + jsoff_t cap = dense_capacity(js, doff); 16158 + if (len >= cap) { 16159 + doff = dense_grow(js, arr, len + 1); 16160 + if (doff == 0) return js_mkerr(js, "oom"); 16161 + } 16162 + dense_set(js, doff, len, args[i]); 16163 + len++; 16164 + dense_set_length(js, doff, len); 16165 + } 16166 + return tov((double) len); 16119 16167 } 16120 16168 16169 + jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16170 + 16121 16171 for (int i = 0; i < nargs; i++) { 16122 16172 char idxstr[16]; 16123 16173 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); ··· 16134 16184 void js_arr_push(struct js *js, jsval_t arr, jsval_t val) { 16135 16185 arr = resolveprop(js, arr); 16136 16186 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) return; 16187 + 16188 + jsoff_t doff = get_dense_buf(js, arr); 16189 + if (doff) { 16190 + jsoff_t len = dense_length(js, doff); 16191 + jsoff_t cap = dense_capacity(js, doff); 16192 + if (len >= cap) { 16193 + doff = dense_grow(js, arr, len + 1); 16194 + if (doff == 0) return; 16195 + } 16196 + dense_set(js, doff, len, val); 16197 + dense_set_length(js, doff, len + 1); 16198 + return; 16199 + } 16137 16200 16138 16201 jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16139 16202 jsoff_t len = 0; ··· 16174 16237 return result; 16175 16238 } 16176 16239 16240 + jsoff_t doff = get_dense_buf(js, arr); 16241 + if (doff) { 16242 + jsoff_t len = dense_length(js, doff); 16243 + if (len == 0) return js_mkundef(); 16244 + len--; 16245 + jsval_t result = dense_get(js, doff, len); 16246 + if (is_empty_slot(result)) result = js_mkundef(); 16247 + dense_set(js, doff, len, T_EMPTY); 16248 + dense_set_length(js, doff, len); 16249 + return result; 16250 + } 16251 + 16177 16252 jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16178 16253 jsoff_t len = 0; 16179 16254 ··· 16221 16296 return js_mkerr(js, "slice called on non-array"); 16222 16297 } 16223 16298 16224 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16225 - jsoff_t len = 0; 16226 - 16227 - if (off != 0) { 16228 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16229 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16230 - } 16299 + jsoff_t len = get_array_length(js, arr); 16231 16300 16232 16301 jsoff_t start = 0, end = len; 16233 16302 double dlen = D(len); ··· 16253 16322 jsoff_t result_idx = 0; 16254 16323 16255 16324 for (jsoff_t i = start; i < end; i++) { 16256 - char idxstr[16]; 16257 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 16258 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 16259 - if (elem_off != 0) { 16260 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 16261 - size_t result_idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)result_idx); 16262 - jsval_t key = js_mkstr(js, idxstr, result_idxlen); 16263 - js_setprop(js, result, key, elem); 16264 - } 16325 + jsval_t elem = arr_get(js, arr, i); 16326 + arr_set(js, result, result_idx, elem); 16265 16327 result_idx++; 16266 16328 } 16267 16329 16268 - jsval_t len_key = js_mkstr(js, "length", 6); 16269 - js_setprop(js, result, len_key, tov((double) result_idx)); 16270 16330 return mkval(T_ARR, vdata(result)); 16271 16331 } 16272 16332 ··· 16290 16350 } 16291 16351 } 16292 16352 16293 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16294 - jsoff_t len = 0; 16295 - 16296 - if (off != 0) { 16297 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16298 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16299 - } 16353 + jsoff_t len = get_array_length(js, arr); 16300 16354 16301 16355 if (len == 0) return js_mkstr(js, "", 0); 16302 16356 ··· 16306 16360 if (!result) return js_mkerr(js, "oom"); 16307 16361 16308 16362 for (jsoff_t i = 0; i < len; i++) { 16309 - char idxstr[16]; 16310 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 16311 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 16312 - 16313 16363 if (i > 0) { 16314 16364 if (result_len + sep_len >= capacity) { 16315 16365 capacity = (result_len + sep_len + 1) * 2; ··· 16321 16371 result_len += sep_len; 16322 16372 } 16323 16373 16324 - if (elem_off != 0) { 16325 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 16374 + { 16375 + jsval_t elem = arr_get(js, arr, i); 16326 16376 uint8_t et = vtype(elem); 16327 16377 if (et == T_NULL || et == T_UNDEF) continue; 16328 16378 ··· 16386 16436 if (nargs == 0) return mkval(T_BOOL, 0); 16387 16437 jsval_t search = args[0]; 16388 16438 16389 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16390 - jsoff_t len = 0; 16391 - 16392 - if (len_off != 0) { 16393 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16394 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16395 - } 16439 + jsoff_t len = get_array_length(js, arr); 16396 16440 if (len == 0) return mkval(T_BOOL, 0); 16397 16441 16398 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16399 - const char *key; size_t key_len; jsval_t val; 16442 + jsoff_t start = 0; 16443 + if (nargs >= 2 && vtype(args[1]) == T_NUM) { 16444 + int s = (int) tod(args[1]); 16445 + if (s < 0) s = (int)len + s; 16446 + if (s < 0) s = 0; 16447 + start = (jsoff_t) s; 16448 + } 16400 16449 16401 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16402 - unsigned long parsed_idx; 16403 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16450 + for (jsoff_t i = start; i < len; i++) { 16451 + jsval_t val = arr_get(js, arr, i); 16404 16452 16405 16453 if (vtype(val) == vtype(search)) { 16406 16454 bool match = false; 16407 - if (vtype(val) == T_NUM && tod(val) == tod(search)) match = true; 16455 + if (vtype(val) == T_NUM) { 16456 + if (isnan(tod(val)) && isnan(tod(search))) match = true; 16457 + else if (tod(val) == tod(search)) match = true; 16458 + } 16408 16459 else if (vtype(val) == T_BOOL && vdata(val) == vdata(search)) match = true; 16409 16460 else if (vtype(val) == T_STR) { 16410 16461 jsoff_t vl, vo = vstr(js, val, &vl); ··· 16413 16464 } 16414 16465 else if ((vtype(val) == T_OBJ || vtype(val) == T_ARR || vtype(val) == T_FUNC) && vdata(val) == vdata(search)) match = true; 16415 16466 16416 - if (match) { 16417 - js_prop_iter_end(&iter); 16418 - return mkval(T_BOOL, 1); 16419 - } 16467 + if (match) return mkval(T_BOOL, 1); 16420 16468 } 16469 + else if (vtype(search) == T_UNDEF && vtype(val) == T_UNDEF) return mkval(T_BOOL, 1); 16470 + else if (vtype(search) == T_NULL && vtype(val) == T_NULL) return mkval(T_BOOL, 1); 16421 16471 } 16422 16472 16423 - js_prop_iter_end(&iter); 16424 16473 return mkval(T_BOOL, 0); 16425 16474 } 16426 16475 ··· 16433 16482 jsval_t callback = require_callback(js, args, nargs, "every"); 16434 16483 if (is_err(callback)) return callback; 16435 16484 16436 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16437 - jsoff_t len = 0; 16438 - if (len_off != 0) { 16439 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16440 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16441 - } 16442 - if (len == 0) return mkval(T_BOOL, 1); 16485 + jsoff_t len = get_array_length(js, arr); 16443 16486 16444 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16445 - const char *key; 16446 - size_t key_len; 16447 - jsval_t val; 16448 - 16449 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16450 - unsigned long parsed_idx; 16451 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16452 - 16453 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 16487 + for (jsoff_t i = 0; i < len; i++) { 16488 + if (!arr_has(js, arr, i)) continue; 16489 + jsval_t val = arr_get(js, arr, i); 16490 + jsval_t call_args[3] = { val, tov((double)i), arr }; 16454 16491 jsval_t result = call_js_with_args(js, callback, call_args, 3); 16455 - 16456 - if (is_err(result)) { 16457 - js_prop_iter_end(&iter); 16458 - return result; 16459 - } 16460 - if (!js_truthy(js, result)) { 16461 - js_prop_iter_end(&iter); 16462 - return mkval(T_BOOL, 0); 16463 - } 16492 + if (is_err(result)) return result; 16493 + if (!js_truthy(js, result)) return mkval(T_BOOL, 0); 16464 16494 } 16465 - js_prop_iter_end(&iter); 16466 16495 16467 16496 return mkval(T_BOOL, 1); 16468 16497 } ··· 16476 16505 jsval_t callback = require_callback(js, args, nargs, "forEach"); 16477 16506 if (is_err(callback)) return callback; 16478 16507 16479 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16480 - jsoff_t len = 0; 16481 - if (len_off != 0) { 16482 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16483 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16484 - } 16485 - if (len == 0) return js_mkundef(); 16508 + jsoff_t len = get_array_length(js, arr); 16486 16509 16487 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16488 - const char *key; 16489 - size_t key_len; 16490 - jsval_t val; 16491 - 16492 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16493 - unsigned long parsed_idx; 16494 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16495 - 16496 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 16510 + for (jsoff_t i = 0; i < len; i++) { 16511 + if (!arr_has(js, arr, i)) continue; 16512 + jsval_t val = arr_get(js, arr, i); 16513 + jsval_t call_args[3] = { val, tov((double)i), arr }; 16497 16514 jsval_t result = call_js_with_args(js, callback, call_args, 3); 16498 - 16499 - if (is_err(result)) { 16500 - js_prop_iter_end(&iter); 16501 - return result; 16502 - } 16515 + if (is_err(result)) return result; 16503 16516 } 16504 - js_prop_iter_end(&iter); 16505 16517 16506 16518 return js_mkundef(); 16507 16519 } ··· 16546 16558 return arr; 16547 16559 } 16548 16560 16549 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16550 - jsoff_t len = 0; 16551 - if (len_off != 0) { 16552 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16553 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16561 + jsoff_t len = get_array_length(js, arr); 16562 + if (len <= 1) return arr; 16563 + 16564 + jsoff_t doff = get_dense_buf(js, arr); 16565 + if (doff) { 16566 + for (jsoff_t i = 0; i < len / 2; i++) { 16567 + jsval_t a = dense_get(js, doff, i); 16568 + jsval_t b = dense_get(js, doff, len - 1 - i); 16569 + dense_set(js, doff, i, b); 16570 + dense_set(js, doff, len - 1 - i, a); 16571 + } 16572 + return arr; 16554 16573 } 16555 - if (len <= 1) return arr; 16556 16574 16557 16575 jsval_t *vals = malloc(len * sizeof(jsval_t)); 16558 16576 jsoff_t *offs = malloc(len * sizeof(jsoff_t)); ··· 16598 16616 jsval_t callback = require_callback(js, args, nargs, "map"); 16599 16617 if (is_err(callback)) return callback; 16600 16618 16601 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16602 - jsoff_t len = 0; 16603 - if (len_off != 0) { 16604 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16605 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16606 - } 16619 + jsoff_t len = get_array_length(js, arr); 16607 16620 16608 16621 jsval_t result = mkarr(js); 16609 16622 if (is_err(result)) return result; 16610 16623 16611 - if (len == 0) { 16612 - js_mkprop_fast(js, result, "length", 6, tov(0.0)); 16613 - return mkval(T_ARR, vdata(result)); 16614 - } 16615 - 16616 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16617 - const char *key; 16618 - size_t key_len; 16619 - jsval_t val; 16620 - 16621 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16622 - unsigned long parsed_idx; 16623 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16624 - 16625 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 16624 + for (jsoff_t i = 0; i < len; i++) { 16625 + if (!arr_has(js, arr, i)) continue; 16626 + jsval_t val = arr_get(js, arr, i); 16627 + jsval_t call_args[3] = { val, tov((double)i), arr }; 16626 16628 jsval_t mapped = call_js_with_args(js, callback, call_args, 3); 16627 - 16628 - if (is_err(mapped)) { 16629 - js_prop_iter_end(&iter); 16630 - return mapped; 16631 - } 16632 - 16633 - char idxstr[16]; 16634 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), parsed_idx); 16635 - js_mkprop_fast(js, result, idxstr, idxlen, mapped); 16629 + if (is_err(mapped)) return mapped; 16630 + arr_set(js, result, i, mapped); 16636 16631 } 16637 - js_prop_iter_end(&iter); 16638 16632 16639 - js_mkprop_fast(js, result, "length", 6, tov((double)len)); 16640 16633 return mkval(T_ARR, vdata(result)); 16641 16634 } 16642 16635 ··· 16649 16642 jsval_t callback = require_callback(js, args, nargs, "filter"); 16650 16643 if (is_err(callback)) return callback; 16651 16644 16652 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16653 - jsoff_t len = 0; 16654 - if (len_off != 0) { 16655 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16656 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16657 - } 16645 + jsoff_t len = get_array_length(js, arr); 16658 16646 16659 16647 jsval_t result = mkarr(js); 16660 16648 if (is_err(result)) return result; 16661 16649 16662 - if (len == 0) { 16663 - js_mkprop_fast(js, result, "length", 6, tov(0.0)); 16664 - return mkval(T_ARR, vdata(result)); 16665 - } 16666 - 16667 16650 jsoff_t result_idx = 0; 16668 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16669 - const char *key; 16670 - size_t key_len; 16671 - jsval_t val; 16672 16651 16673 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16674 - unsigned long parsed_idx; 16675 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16676 - 16677 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 16652 + for (jsoff_t i = 0; i < len; i++) { 16653 + if (!arr_has(js, arr, i)) continue; 16654 + jsval_t val = arr_get(js, arr, i); 16655 + jsval_t call_args[3] = { val, tov((double)i), arr }; 16678 16656 jsval_t test = call_js_with_args(js, callback, call_args, 3); 16679 - 16680 - if (is_err(test)) { 16681 - js_prop_iter_end(&iter); 16682 - return test; 16683 - } 16684 - 16657 + if (is_err(test)) return test; 16685 16658 if (js_truthy(js, test)) { 16686 - char idxstr[16]; 16687 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)result_idx); 16688 - js_mkprop_fast(js, result, idxstr, idxlen, val); 16659 + arr_set(js, result, result_idx, val); 16689 16660 result_idx++; 16690 16661 } 16691 16662 } 16692 - js_prop_iter_end(&iter); 16693 16663 16694 - js_mkprop_fast(js, result, "length", 6, tov((double)result_idx)); 16695 16664 return mkval(T_ARR, vdata(result)); 16696 16665 } 16697 16666 ··· 16705 16674 if (is_err(callback)) return callback; 16706 16675 bool has_initial = (nargs >= 2); 16707 16676 16708 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16709 - jsoff_t len = 0; 16710 - if (len_off != 0) { 16711 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16712 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16713 - } 16714 - 16715 - if (len == 0) { 16716 - if (has_initial) return args[1]; 16717 - return js_mkerr(js, "reduce of empty array with no initial value"); 16718 - } 16677 + jsoff_t len = get_array_length(js, arr); 16719 16678 16720 16679 jsval_t accumulator = has_initial ? args[1] : js_mkundef(); 16721 16680 bool first = !has_initial; 16722 16681 16723 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16724 - const char *key; 16725 - size_t key_len; 16726 - jsval_t val; 16727 - 16728 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16729 - unsigned long parsed_idx; 16730 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16731 - 16732 - if (first) { 16733 - accumulator = val; 16734 - first = false; 16735 - continue; 16736 - } 16737 - 16738 - jsval_t call_args[4] = { accumulator, val, tov((double)parsed_idx), arr }; 16682 + for (jsoff_t i = 0; i < len; i++) { 16683 + if (!arr_has(js, arr, i)) continue; 16684 + jsval_t val = arr_get(js, arr, i); 16685 + if (first) { accumulator = val; first = false; continue; } 16686 + jsval_t call_args[4] = { accumulator, val, tov((double)i), arr }; 16739 16687 accumulator = call_js_with_args(js, callback, call_args, 4); 16740 - 16741 - if (is_err(accumulator)) { 16742 - js_prop_iter_end(&iter); 16743 - return accumulator; 16744 - } 16688 + if (is_err(accumulator)) return accumulator; 16745 16689 } 16746 16690 16747 - js_prop_iter_end(&iter); 16748 16691 if (first) return js_mkerr(js, "reduce of empty array with no initial value"); 16749 - 16750 16692 return accumulator; 16751 16693 } 16752 16694 16753 16695 static void flat_helper(struct js *js, jsval_t arr, jsval_t result, jsoff_t *result_idx, int depth) { 16754 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16755 - jsoff_t len = 0; 16756 - if (len_off != 0) { 16757 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16758 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16759 - } 16696 + jsoff_t len = get_array_length(js, arr); 16760 16697 if (len == 0) return; 16761 16698 16762 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16763 - const char *key; 16764 - size_t key_len; 16765 - jsval_t val; 16766 - 16767 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16768 - unsigned long parsed_idx; 16769 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16699 + for (jsoff_t i = 0; i < len; i++) { 16700 + if (!arr_has(js, arr, i)) continue; 16701 + jsval_t val = arr_get(js, arr, i); 16770 16702 16771 16703 if (depth > 0 && (vtype(val) == T_ARR || vtype(val) == T_OBJ)) { 16772 16704 flat_helper(js, val, result, result_idx, depth - 1); 16773 16705 } else { 16774 - char idxstr[16]; 16775 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)*result_idx); 16776 - js_mkprop_fast(js, result, idxstr, idxlen, val); 16706 + arr_set(js, result, *result_idx, val); 16777 16707 (*result_idx)++; 16778 16708 } 16779 16709 } 16780 - 16781 - js_prop_iter_end(&iter); 16782 16710 } 16783 16711 16784 16712 static jsval_t builtin_array_flat(struct js *js, jsval_t *args, int nargs) { ··· 16799 16727 16800 16728 flat_helper(js, arr, result, &result_idx, depth); 16801 16729 16802 - jsval_t len_key = js_mkstr(js, "length", 6); 16803 - js_setprop(js, result, len_key, tov((double) result_idx)); 16804 16730 return mkval(T_ARR, vdata(result)); 16805 16731 } 16806 16732 ··· 16814 16740 if (is_err(result)) return result; 16815 16741 jsoff_t result_idx = 0; 16816 16742 16817 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16818 - jsoff_t len = 0; 16819 - if (off != 0) { 16820 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16821 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16822 - } 16743 + jsoff_t len = get_array_length(js, arr); 16823 16744 16824 16745 for (jsoff_t i = 0; i < len; i++) { 16825 - char idxstr[16]; 16826 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 16827 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 16828 - if (elem_off != 0) { 16829 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 16830 - char res_idx[16]; 16831 - size_t res_idx_len = uint_to_str(res_idx, sizeof(res_idx), (unsigned)result_idx); 16832 - js_mkprop_fast(js, result, res_idx, res_idx_len, elem); 16833 - } 16746 + jsval_t elem = arr_get(js, arr, i); 16747 + arr_set(js, result, result_idx, elem); 16834 16748 result_idx++; 16835 16749 } 16836 16750 16837 16751 for (int a = 0; a < nargs; a++) { 16838 16752 jsval_t arg = args[a]; 16839 16753 if (vtype(arg) == T_ARR || vtype(arg) == T_OBJ) { 16840 - jsoff_t arg_off = lkp_interned(js, arg, INTERN_LENGTH, 6); 16841 - jsoff_t arg_len = 0; 16842 - if (arg_off != 0) { 16843 - jsval_t len_val = resolveprop(js, mkval(T_PROP, arg_off)); 16844 - if (vtype(len_val) == T_NUM) arg_len = (jsoff_t) tod(len_val); 16845 - } 16754 + jsoff_t arg_len = get_array_length(js, arg); 16846 16755 16847 16756 for (jsoff_t i = 0; i < arg_len; i++) { 16848 - char idxstr[16]; 16849 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 16850 - jsoff_t elem_off = lkp(js, arg, idxstr, idxlen); 16851 - if (elem_off != 0) { 16852 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 16853 - char res_idx[16]; 16854 - size_t res_idx_len = uint_to_str(res_idx, sizeof(res_idx), (unsigned)result_idx); 16855 - js_mkprop_fast(js, result, res_idx, res_idx_len, elem); 16856 - } 16757 + jsval_t elem = arr_get(js, arg, i); 16758 + arr_set(js, result, result_idx, elem); 16857 16759 result_idx++; 16858 16760 } 16859 16761 } else { 16860 - char res_idx[16]; 16861 - size_t res_idx_len = uint_to_str(res_idx, sizeof(res_idx), (unsigned)result_idx); 16862 - js_mkprop_fast(js, result, res_idx, res_idx_len, arg); 16762 + arr_set(js, result, result_idx, arg); 16863 16763 result_idx++; 16864 16764 } 16865 16765 } 16866 16766 16867 - js_mkprop_fast(js, result, "length", 6, tov((double)result_idx)); 16868 16767 return mkval(T_ARR, vdata(result)); 16869 16768 } 16870 16769 ··· 16876 16775 16877 16776 if (nargs == 0 || vtype(args[0]) != T_NUM) return js_mkundef(); 16878 16777 16879 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16880 - jsoff_t len = 0; 16881 - if (off != 0) { 16882 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16883 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16884 - } 16778 + jsoff_t len = get_array_length(js, arr); 16885 16779 16886 16780 int idx = (int) tod(args[0]); 16887 16781 if (idx < 0) idx = (int)len + idx; 16888 16782 if (idx < 0 || (jsoff_t)idx >= len) return js_mkundef(); 16889 16783 16890 - char idxstr[16]; 16891 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 16892 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 16893 - return elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 16784 + return arr_get(js, arr, (jsoff_t)idx); 16894 16785 } 16895 16786 16896 16787 static jsval_t builtin_array_fill(struct js *js, jsval_t *args, int nargs) { ··· 16920 16811 if (end > len) end = len; 16921 16812 16922 16813 for (jsoff_t i = start; i < end; i++) { 16923 - char idxstr[16]; 16924 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 16925 - jsval_t key = js_mkstr(js, idxstr, idxlen); 16926 - js_setprop(js, arr, key, value); 16814 + arr_set(js, arr, i, value); 16927 16815 } 16928 16816 16929 16817 return arr; ··· 16938 16826 jsval_t callback = require_callback(js, args, nargs, name); 16939 16827 if (is_err(callback)) return callback; 16940 16828 16941 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16942 - jsoff_t len = 0; 16943 - if (len_off != 0) { 16944 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16945 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16946 - } 16829 + jsoff_t len = get_array_length(js, arr); 16947 16830 if (len == 0) return return_index ? tov(-1) : js_mkundef(); 16948 16831 16949 - ant_iter_t iter = js_prop_iter_begin(js, arr); 16950 - const char *key; 16951 - size_t key_len; 16952 - jsval_t val; 16953 - 16954 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16955 - unsigned long parsed_idx; 16956 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16832 + for (jsoff_t i = 0; i < len; i++) { 16833 + jsval_t val = arr_get(js, arr, i); 16957 16834 16958 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 16835 + jsval_t call_args[3] = { val, tov((double)i), arr }; 16959 16836 jsval_t result = call_js_with_args(js, callback, call_args, 3); 16960 16837 16961 - if (is_err(result)) { 16962 - js_prop_iter_end(&iter); 16963 - return result; 16964 - } 16965 - if (js_truthy(js, result)) { 16966 - js_prop_iter_end(&iter); 16967 - return return_index ? tov((double)parsed_idx) : val; 16968 - } 16838 + if (is_err(result)) return result; 16839 + if (js_truthy(js, result)) return return_index ? tov((double)i) : val; 16969 16840 } 16970 - js_prop_iter_end(&iter); 16971 16841 16972 16842 return return_index ? tov(-1) : js_mkundef(); 16973 16843 } ··· 16989 16859 jsval_t callback = require_callback(js, args, nargs, name); 16990 16860 if (is_err(callback)) return callback; 16991 16861 16992 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16993 - jsoff_t len = 0; 16994 - if (len_off != 0) { 16995 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 16996 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16997 - } 16862 + jsoff_t len = get_array_length(js, arr); 16998 16863 if (len == 0) return return_index ? tov(-1) : js_mkundef(); 16999 16864 17000 - jsval_t *vals = malloc(len * sizeof(jsval_t)); 17001 - unsigned long *idxs = malloc(len * sizeof(unsigned)); 17002 - if (!vals || !idxs) { free(vals); free(idxs); return js_mkerr(js, "out of memory"); } 17003 - 17004 - jsoff_t count = 0; 17005 - ant_iter_t iter = js_prop_iter_begin(js, arr); 17006 - const char *key; size_t key_len; jsval_t val; 17007 - 17008 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 17009 - unsigned long parsed_idx; 17010 - if (!parse_array_index(key, key_len, len, &parsed_idx) || count >= len) continue; 16865 + for (jsoff_t i = len; i > 0; i--) { 16866 + jsval_t val = arr_get(js, arr, i - 1); 17011 16867 17012 - vals[count] = val; 17013 - idxs[count] = parsed_idx; 17014 - count++; 17015 - } 17016 - js_prop_iter_end(&iter); 17017 - 17018 - for (jsoff_t i = count; i > 0; i--) { 17019 - jsval_t call_args[3] = { vals[i-1], tov((double)idxs[i-1]), arr }; 16868 + jsval_t call_args[3] = { val, tov((double)(i - 1)), arr }; 17020 16869 jsval_t result = call_js_with_args(js, callback, call_args, 3); 17021 16870 17022 - if (is_err(result)) { 17023 - free(vals); free(idxs); 17024 - return result; 17025 - } 17026 - if (js_truthy(js, result)) { 17027 - jsval_t found_val = vals[i-1]; 17028 - unsigned long found_idx = idxs[i-1]; 17029 - free(vals); free(idxs); 17030 - return return_index ? tov((double)found_idx) : found_val; 17031 - } 16871 + if (is_err(result)) return result; 16872 + if (js_truthy(js, result)) return return_index ? tov((double)(i - 1)) : val; 17032 16873 } 17033 16874 17034 - free(vals); free(idxs); 17035 16875 return return_index ? tov(-1) : js_mkundef(); 17036 16876 } 17037 16877 ··· 17053 16893 } 17054 16894 17055 16895 jsval_t callback = args[0]; 17056 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17057 - jsoff_t len = 0; 17058 - if (off != 0) { 17059 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17060 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17061 - } 16896 + jsoff_t len = get_array_length(js, arr); 17062 16897 17063 16898 jsval_t result = mkarr(js); 17064 16899 if (is_err(result)) return result; 17065 16900 jsoff_t result_idx = 0; 17066 16901 17067 16902 for (jsoff_t i = 0; i < len; i++) { 17068 - char idxstr[16]; 17069 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17070 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17071 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 16903 + jsval_t elem = arr_get(js, arr, i); 17072 16904 jsval_t call_args[3] = { elem, tov((double)i), arr }; 17073 16905 jsval_t mapped = call_js_with_args(js, callback, call_args, 3); 17074 16906 if (is_err(mapped)) return mapped; 17075 16907 17076 16908 if (vtype(mapped) == T_ARR || vtype(mapped) == T_OBJ) { 17077 - jsoff_t m_off = lkp_interned(js, mapped, INTERN_LENGTH, 6); 17078 - jsoff_t m_len = 0; 17079 - if (m_off != 0) { 17080 - jsval_t m_len_val = resolveprop(js, mkval(T_PROP, m_off)); 17081 - if (vtype(m_len_val) == T_NUM) m_len = (jsoff_t) tod(m_len_val); 17082 - } 16909 + jsoff_t m_len = get_array_length(js, mapped); 17083 16910 for (jsoff_t j = 0; j < m_len; j++) { 17084 - char jstr[16]; 17085 - snprintf(jstr, sizeof(jstr), "%u", (unsigned) j); 17086 - jsoff_t m_elem_off = lkp(js, mapped, jstr, strlen(jstr)); 17087 - if (m_elem_off != 0) { 17088 - jsval_t m_elem = resolveprop(js, mkval(T_PROP, m_elem_off)); 17089 - char res_idx[16]; 17090 - snprintf(res_idx, sizeof(res_idx), "%u", (unsigned) result_idx); 17091 - jsval_t key = js_mkstr(js, res_idx, strlen(res_idx)); 17092 - js_setprop(js, result, key, m_elem); 17093 - } 16911 + jsval_t m_elem = arr_get(js, mapped, j); 16912 + arr_set(js, result, result_idx, m_elem); 17094 16913 result_idx++; 17095 16914 } 17096 16915 } else { 17097 - char res_idx[16]; 17098 - snprintf(res_idx, sizeof(res_idx), "%u", (unsigned) result_idx); 17099 - jsval_t key = js_mkstr(js, res_idx, strlen(res_idx)); 17100 - js_setprop(js, result, key, mapped); 16916 + arr_set(js, result, result_idx, mapped); 17101 16917 result_idx++; 17102 16918 } 17103 16919 } 17104 16920 17105 - jsval_t len_key = js_mkstr(js, "length", 6); 17106 - js_setprop(js, result, len_key, tov((double) result_idx)); 17107 16921 return mkval(T_ARR, vdata(result)); 17108 16922 } 17109 16923 ··· 17148 16962 if (nargs == 0) return tov(-1); 17149 16963 17150 16964 jsval_t search = args[0]; 17151 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17152 - jsoff_t len = 0; 17153 - if (off != 0) { 17154 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17155 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17156 - } 16965 + jsoff_t len = get_array_length(js, arr); 17157 16966 17158 16967 jsoff_t start = 0; 17159 16968 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 17164 16973 } 17165 16974 17166 16975 for (jsoff_t i = start; i < len; i++) { 17167 - char idxstr[16]; 17168 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17169 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17170 - if (elem_off != 0) { 17171 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17172 - if (vtype(elem) == vtype(search)) { 17173 - if (vtype(elem) == T_NUM && tod(elem) == tod(search)) return tov((double)i); 17174 - if (vtype(elem) == T_BOOL && vdata(elem) == vdata(search)) return tov((double)i); 17175 - if (vtype(elem) == T_STR) { 17176 - jsoff_t el, eo = vstr(js, elem, &el); 17177 - jsoff_t sl, so = vstr(js, search, &sl); 17178 - if (el == sl && memcmp(&js->mem[eo], &js->mem[so], el) == 0) return tov((double)i); 17179 - } 17180 - if ((vtype(elem) == T_OBJ || vtype(elem) == T_ARR || vtype(elem) == T_FUNC) && vdata(elem) == vdata(search)) return tov((double)i); 16976 + jsval_t elem = arr_get(js, arr, i); 16977 + if (vtype(elem) == T_UNDEF && !arr_has(js, arr, i)) continue; 16978 + if (vtype(elem) == vtype(search)) { 16979 + if (vtype(elem) == T_NUM && tod(elem) == tod(search)) return tov((double)i); 16980 + if (vtype(elem) == T_BOOL && vdata(elem) == vdata(search)) return tov((double)i); 16981 + if (vtype(elem) == T_STR) { 16982 + jsoff_t el, eo = vstr(js, elem, &el); 16983 + jsoff_t sl, so = vstr(js, search, &sl); 16984 + if (el == sl && memcmp(&js->mem[eo], &js->mem[so], el) == 0) return tov((double)i); 17181 16985 } 16986 + if ((vtype(elem) == T_OBJ || vtype(elem) == T_ARR || vtype(elem) == T_FUNC) && vdata(elem) == vdata(search)) return tov((double)i); 17182 16987 } 17183 16988 } 17184 16989 return tov(-1); ··· 17192 16997 if (nargs == 0) return tov(-1); 17193 16998 17194 16999 jsval_t search = args[0]; 17195 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17196 - jsoff_t len = 0; 17197 - if (off != 0) { 17198 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17199 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17200 - } 17000 + jsoff_t len = get_array_length(js, arr); 17201 17001 17202 17002 int start = (int)len - 1; 17203 17003 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 17207 17007 if (start >= (int)len) start = (int)len - 1; 17208 17008 17209 17009 for (int i = start; i >= 0; i--) { 17210 - char idxstr[16]; 17211 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17212 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17213 - if (elem_off != 0) { 17214 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17215 - if (vtype(elem) == vtype(search)) { 17216 - if (vtype(elem) == T_NUM && tod(elem) == tod(search)) return tov((double)i); 17217 - if (vtype(elem) == T_BOOL && vdata(elem) == vdata(search)) return tov((double)i); 17218 - if (vtype(elem) == T_STR) { 17219 - jsoff_t el, eo = vstr(js, elem, &el); 17220 - jsoff_t sl, so = vstr(js, search, &sl); 17221 - if (el == sl && memcmp(&js->mem[eo], &js->mem[so], el) == 0) return tov((double)i); 17222 - } 17223 - if ((vtype(elem) == T_OBJ || vtype(elem) == T_ARR || vtype(elem) == T_FUNC) && vdata(elem) == vdata(search)) return tov((double)i); 17010 + jsval_t elem = arr_get(js, arr, (jsoff_t)i); 17011 + if (vtype(elem) == T_UNDEF && !arr_has(js, arr, (jsoff_t)i)) continue; 17012 + if (vtype(elem) == vtype(search)) { 17013 + if (vtype(elem) == T_NUM && tod(elem) == tod(search)) return tov((double)i); 17014 + if (vtype(elem) == T_BOOL && vdata(elem) == vdata(search)) return tov((double)i); 17015 + if (vtype(elem) == T_STR) { 17016 + jsoff_t el, eo = vstr(js, elem, &el); 17017 + jsoff_t sl, so = vstr(js, search, &sl); 17018 + if (el == sl && memcmp(&js->mem[eo], &js->mem[so], el) == 0) return tov((double)i); 17224 17019 } 17020 + if ((vtype(elem) == T_OBJ || vtype(elem) == T_ARR || vtype(elem) == T_FUNC) && vdata(elem) == vdata(search)) return tov((double)i); 17225 17021 } 17226 17022 } 17227 17023 return tov(-1); ··· 17237 17033 } 17238 17034 17239 17035 jsval_t callback = args[0]; 17240 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17241 - jsoff_t len = 0; 17242 - if (off != 0) { 17243 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17244 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17245 - } 17036 + jsoff_t len = get_array_length(js, arr); 17246 17037 17247 17038 int start_idx = (int)len - 1; 17248 17039 jsval_t accumulator; ··· 17251 17042 accumulator = args[1]; 17252 17043 } else { 17253 17044 if (len == 0) return js_mkerr(js, "reduceRight of empty array with no initial value"); 17254 - char idxstr[16]; 17255 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)(len - 1)); 17256 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17257 - accumulator = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17045 + accumulator = arr_get(js, arr, len - 1); 17258 17046 start_idx = (int)len - 2; 17259 17047 } 17260 17048 17261 17049 for (int i = start_idx; i >= 0; i--) { 17262 - char idxstr[16]; 17263 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17264 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17265 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17050 + jsval_t elem = arr_get(js, arr, (jsoff_t)i); 17266 17051 jsval_t call_args[4] = { accumulator, elem, tov((double)i), arr }; 17267 17052 accumulator = call_js_with_args(js, callback, call_args, 4); 17268 17053 if (is_err(accumulator)) return accumulator; ··· 17282 17067 jsoff_t len = proxy_aware_length(js, arr); 17283 17068 if (len == 0) return js_mkundef(); 17284 17069 17070 + jsoff_t doff = get_dense_buf(js, arr); 17071 + if (doff && !is_proxy(js, arr)) { 17072 + jsoff_t d_len = dense_length(js, doff); 17073 + if (d_len == 0) return js_mkundef(); 17074 + jsval_t first = dense_get(js, doff, 0); 17075 + if (is_empty_slot(first)) first = js_mkundef(); 17076 + memmove(&js->mem[doff + sizeof(jsoff_t) * 2], 17077 + &js->mem[doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t)], 17078 + sizeof(jsval_t) * (d_len - 1)); 17079 + dense_set(js, doff, d_len - 1, T_EMPTY); 17080 + dense_set_length(js, doff, d_len - 1); 17081 + return first; 17082 + } 17083 + 17285 17084 jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17286 17085 jsoff_t first_off = lkp(js, read_from, "0", 1); 17287 17086 jsval_t first = first_off ? resolveprop(js, mkval(T_PROP, first_off)) : js_mkundef(); ··· 17311 17110 } 17312 17111 17313 17112 jsoff_t len = proxy_aware_length(js, arr); 17113 + 17114 + jsoff_t doff = get_dense_buf(js, arr); 17115 + if (doff && !is_proxy(js, arr)) { 17116 + jsoff_t d_len = dense_length(js, doff); 17117 + jsoff_t new_len = d_len + nargs; 17118 + jsoff_t cap = dense_capacity(js, doff); 17119 + if (new_len > cap) { 17120 + doff = dense_grow(js, arr, new_len); 17121 + if (doff == 0) return js_mkerr(js, "oom"); 17122 + } 17123 + memmove(&js->mem[doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * nargs], 17124 + &js->mem[doff + sizeof(jsoff_t) * 2], 17125 + sizeof(jsval_t) * d_len); 17126 + for (int i = 0; i < nargs; i++) 17127 + dense_set(js, doff, (jsoff_t)i, args[i]); 17128 + dense_set_length(js, doff, new_len); 17129 + return tov((double) new_len); 17130 + } 17131 + 17314 17132 jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17315 17133 17316 17134 for (int i = (int)len - 1; i >= 0; i--) { ··· 17347 17165 jsval_t callback = require_callback(js, args, nargs, "some"); 17348 17166 if (is_err(callback)) return callback; 17349 17167 17350 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17351 - jsoff_t len = 0; 17352 - if (len_off != 0) { 17353 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 17354 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 17355 - } 17168 + jsoff_t len = get_array_length(js, arr); 17356 17169 if (len == 0) return mkval(T_BOOL, 0); 17357 17170 17358 - ant_iter_t iter = js_prop_iter_begin(js, arr); 17359 - const char *key; 17360 - size_t key_len; 17361 - jsval_t val; 17362 - 17363 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 17364 - unsigned long parsed_idx; 17365 - if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 17171 + for (jsoff_t i = 0; i < len; i++) { 17172 + if (!arr_has(js, arr, i)) continue; 17173 + jsval_t val = arr_get(js, arr, i); 17366 17174 17367 - jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; 17175 + jsval_t call_args[3] = { val, tov((double)i), arr }; 17368 17176 jsval_t result = call_js_with_args(js, callback, call_args, 3); 17369 17177 17370 - if (is_err(result)) { 17371 - js_prop_iter_end(&iter); 17372 - return result; 17373 - } 17374 - if (js_truthy(js, result)) { 17375 - js_prop_iter_end(&iter); 17376 - return mkval(T_BOOL, 1); 17377 - } 17178 + if (is_err(result)) return result; 17179 + if (js_truthy(js, result)) return mkval(T_BOOL, 1); 17378 17180 } 17379 - js_prop_iter_end(&iter); 17380 17181 17381 17182 return mkval(T_BOOL, 0); 17382 17183 } ··· 17397 17198 else if (t != T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "compareFn must be a function or undefined"); 17398 17199 } 17399 17200 17400 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17401 - if (off != 0) { 17402 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17403 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 17404 - } 17201 + len = get_array_length(js, arr); 17405 17202 if (len == 0) return arr; 17406 17203 17407 - vals = malloc(len * sizeof(jsval_t)); 17408 - offs = malloc(len * sizeof(jsoff_t)); 17409 - if (!vals || !offs) goto oom; 17410 - 17411 - ant_iter_t iter = js_prop_iter_begin(js, arr); 17412 - const char *key; 17413 - size_t key_len; 17414 - jsval_t val; 17415 - 17416 - while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 17417 - if (key_len == 0 || key[0] > '9' || key[0] < '0') continue; 17204 + jsoff_t doff = get_dense_buf(js, arr); 17205 + if (doff) { 17206 + vals = malloc(len * sizeof(jsval_t)); 17207 + if (!vals) goto oom; 17208 + for (jsoff_t i = 0; i < len; i++) { 17209 + jsval_t v = dense_get(js, doff, i); 17210 + if (is_empty_slot(v) || vtype(v) == T_UNDEF) undef_count++; 17211 + else vals[count++] = v; 17212 + } 17213 + } else { 17214 + vals = malloc(len * sizeof(jsval_t)); 17215 + offs = malloc(len * sizeof(jsoff_t)); 17216 + if (!vals || !offs) goto oom; 17418 17217 17419 - unsigned idx = 0; 17420 - bool valid = true; 17421 - for (size_t i = 0; i < key_len && valid; i++) { 17422 - if (key[i] < '0' || key[i] > '9') valid = false; 17423 - else idx = idx * 10 + (key[i] - '0'); 17218 + ant_iter_t iter = js_prop_iter_begin(js, arr); 17219 + const char *key; 17220 + size_t key_len; 17221 + jsval_t val; 17222 + 17223 + while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 17224 + if (key_len == 0 || key[0] > '9' || key[0] < '0') continue; 17225 + 17226 + unsigned idx = 0; 17227 + bool valid = true; 17228 + for (size_t i = 0; i < key_len && valid; i++) { 17229 + if (key[i] < '0' || key[i] > '9') valid = false; 17230 + else idx = idx * 10 + (key[i] - '0'); 17231 + } 17232 + if (!valid || idx >= len || (count + undef_count) >= len) continue; 17233 + 17234 + offs[count + undef_count] = iter.off; 17235 + if (vtype(val) == T_UNDEF) undef_count++; 17236 + else vals[count++] = val; 17424 17237 } 17425 - if (!valid || idx >= len || (count + undef_count) >= len) continue; 17426 17238 17427 - offs[count + undef_count] = iter.off; 17428 - if (vtype(val) == T_UNDEF) undef_count++; 17429 - else vals[count++] = val; 17239 + js_prop_iter_end(&iter); 17430 17240 } 17431 - 17432 - js_prop_iter_end(&iter); 17433 17241 if (count <= 1) goto writeback; 17434 17242 17435 17243 bool use_keys = (vtype(compareFn) == T_UNDEF); ··· 17490 17298 } 17491 17299 17492 17300 writeback: 17493 - for (jsoff_t i = 0; i < count; i++) 17494 - saveval(js, offs[i] + sizeof(jsoff_t) * 2, vals[i]); 17495 - for (jsoff_t i = 0; i < undef_count; i++) 17496 - saveval(js, offs[count + i] + sizeof(jsoff_t) * 2, js_mkundef()); 17301 + if (doff) { 17302 + for (jsoff_t i = 0; i < count; i++) dense_set(js, doff, i, vals[i]); 17303 + for (jsoff_t i = count; i < count + undef_count; i++) dense_set(js, doff, i, js_mkundef()); 17304 + for (jsoff_t i = count + undef_count; i < len; i++) dense_set(js, doff, i, T_EMPTY); 17305 + } else { 17306 + for (jsoff_t i = 0; i < count; i++) 17307 + saveval(js, offs[i] + sizeof(jsoff_t) * 2, vals[i]); 17308 + for (jsoff_t i = 0; i < undef_count; i++) 17309 + saveval(js, offs[count + i] + sizeof(jsoff_t) * 2, js_mkundef()); 17310 + } 17497 17311 17498 17312 free(temp_keys); 17499 17313 free(temp_vals); ··· 17540 17354 jsval_t removed = mkarr(js); 17541 17355 if (is_err(removed)) return removed; 17542 17356 17357 + jsoff_t doff = get_dense_buf(js, arr); 17358 + if (doff && !is_proxy(js, arr)) { 17359 + for (int i = 0; i < deleteCount; i++) { 17360 + jsval_t elem = arr_get(js, arr, (jsoff_t)(start + i)); 17361 + arr_set(js, removed, (jsoff_t)i, elem); 17362 + } 17363 + 17364 + jsoff_t d_len = dense_length(js, doff); 17365 + int shift = insertCount - deleteCount; 17366 + jsoff_t new_len = (jsoff_t)((int)d_len + shift); 17367 + 17368 + if (shift != 0) { 17369 + if (new_len > dense_capacity(js, doff)) { 17370 + doff = dense_grow(js, arr, new_len); 17371 + if (doff == 0) return js_mkerr(js, "oom"); 17372 + } 17373 + jsoff_t move_start = (jsoff_t)(start + deleteCount); 17374 + jsoff_t move_dest = (jsoff_t)(start + insertCount); 17375 + jsoff_t move_count = d_len - move_start; 17376 + if (move_count > 0) memmove( 17377 + &js->mem[doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * move_dest], 17378 + &js->mem[doff + sizeof(jsoff_t) * 2 + sizeof(jsval_t) * move_start], 17379 + sizeof(jsval_t) * move_count 17380 + ); 17381 + } 17382 + 17383 + for (int i = 0; i < insertCount; i++) 17384 + dense_set(js, doff, (jsoff_t)(start + i), args[2 + i]); 17385 + 17386 + if (shift < 0) { 17387 + for (jsoff_t i = new_len; i < d_len; i++) 17388 + dense_set(js, doff, i, T_EMPTY); 17389 + } 17390 + 17391 + dense_set_length(js, doff, new_len); 17392 + if (deleteCount > 0) js->needs_gc = true; 17393 + return mkval(T_ARR, vdata(removed)); 17394 + } 17395 + 17543 17396 for (int i = 0; i < deleteCount; i++) { 17544 17397 char src[16], dst[16]; 17545 17398 snprintf(src, sizeof(src), "%u", (unsigned)(start + i)); ··· 17619 17472 if (end > (int)len) end = (int)len; 17620 17473 int count = end - start; 17621 17474 if (count > (int)len - target) count = (int)len - target; 17475 + if (count <= 0) return arr; 17476 + 17477 + jsoff_t doff = get_dense_buf(js, arr); 17478 + if (doff && !is_proxy(js, arr)) { 17479 + if (start < target) { 17480 + for (int i = count - 1; i >= 0; i--) { 17481 + jsval_t v = dense_get(js, doff, (jsoff_t)(start + i)); 17482 + dense_set(js, doff, (jsoff_t)(target + i), is_empty_slot(v) ? js_mkundef() : v); 17483 + } 17484 + } else { 17485 + for (int i = 0; i < count; i++) { 17486 + jsval_t v = dense_get(js, doff, (jsoff_t)(start + i)); 17487 + dense_set(js, doff, (jsoff_t)(target + i), is_empty_slot(v) ? js_mkundef() : v); 17488 + } 17489 + } 17490 + return arr; 17491 + } 17622 17492 17623 17493 jsval_t *temp = (jsval_t *)malloc(count * sizeof(jsval_t)); 17624 17494 for (int i = 0; i < count; i++) { ··· 17698 17568 17699 17569 if (nargs < 2) return js_mkerr(js, "with requires index and value arguments"); 17700 17570 17701 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17702 - jsoff_t len = 0; 17703 - if (off != 0) { 17704 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17705 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17706 - } 17571 + jsoff_t len = get_array_length(js, arr); 17707 17572 17708 17573 int idx = (int) tod(args[0]); 17709 17574 if (idx < 0) idx = (int)len + idx; ··· 17713 17578 if (is_err(result)) return result; 17714 17579 17715 17580 for (jsoff_t i = 0; i < len; i++) { 17716 - char idxstr[16]; 17717 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17718 - jsval_t elem; 17719 - if ((jsoff_t)idx == i) { 17720 - elem = args[1]; 17721 - } else { 17722 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17723 - elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17724 - } 17725 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17726 - js_setprop(js, result, key, elem); 17581 + jsval_t elem = ((jsoff_t)idx == i) ? args[1] : arr_get(js, arr, i); 17582 + arr_set(js, result, i, elem); 17727 17583 } 17728 17584 17729 - jsval_t len_key = js_mkstr(js, "length", 6); 17730 - js_setprop(js, result, len_key, tov((double) len)); 17731 17585 return mkval(T_ARR, vdata(result)); 17732 17586 } 17733 17587 ··· 17739 17593 return js_mkerr(js, "keys called on non-array"); 17740 17594 } 17741 17595 17742 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17743 - jsoff_t len = 0; 17744 - if (off != 0) { 17745 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17746 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17747 - } 17596 + jsoff_t len = get_array_length(js, arr); 17748 17597 17749 17598 jsval_t result = mkarr(js); 17750 17599 if (is_err(result)) return result; 17751 17600 17752 17601 for (jsoff_t i = 0; i < len; i++) { 17753 - char idxstr[16]; 17754 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17755 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17756 - js_setprop(js, result, key, tov((double) i)); 17602 + arr_set(js, result, i, tov((double) i)); 17757 17603 } 17758 17604 17759 - jsval_t len_key = js_mkstr(js, "length", 6); 17760 - js_setprop(js, result, len_key, tov((double) len)); 17761 17605 return mkval(T_ARR, vdata(result)); 17762 17606 } 17763 17607 ··· 17769 17613 return js_mkerr(js, "values called on non-array"); 17770 17614 } 17771 17615 17772 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17773 - jsoff_t len = 0; 17774 - if (off != 0) { 17775 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17776 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17777 - } 17616 + jsoff_t len = get_array_length(js, arr); 17778 17617 17779 17618 jsval_t result = mkarr(js); 17780 17619 if (is_err(result)) return result; 17781 17620 17782 17621 for (jsoff_t i = 0; i < len; i++) { 17783 - char idxstr[16]; 17784 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17785 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17786 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17787 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17788 - js_setprop(js, result, key, elem); 17622 + arr_set(js, result, i, arr_get(js, arr, i)); 17789 17623 } 17790 17624 17791 - jsval_t len_key = js_mkstr(js, "length", 6); 17792 - js_setprop(js, result, len_key, tov((double) len)); 17793 17625 return mkval(T_ARR, vdata(result)); 17794 17626 } 17795 17627 ··· 17801 17633 return js_mkerr(js, "entries called on non-array"); 17802 17634 } 17803 17635 17804 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17805 - jsoff_t len = 0; 17806 - if (off != 0) { 17807 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17808 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17809 - } 17636 + jsoff_t len = get_array_length(js, arr); 17810 17637 17811 17638 jsval_t result = mkarr(js); 17812 17639 if (is_err(result)) return result; ··· 17815 17642 jsval_t entry = mkarr(js); 17816 17643 if (is_err(entry)) return entry; 17817 17644 17818 - char idxstr[16]; 17819 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17820 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17821 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17645 + jsval_t elem = arr_get(js, arr, i); 17822 17646 17823 - js_setprop(js, entry, js_mkstr(js, "0", 1), tov((double) i)); 17824 - js_setprop(js, entry, js_mkstr(js, "1", 1), elem); 17825 - js_setprop(js, entry, js_mkstr(js, "length", 6), tov(2)); 17647 + arr_set(js, entry, 0, tov((double) i)); 17648 + arr_set(js, entry, 1, elem); 17826 17649 17827 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17828 - js_setprop(js, result, key, mkval(T_ARR, vdata(entry))); 17650 + arr_set(js, result, i, mkval(T_ARR, vdata(entry))); 17829 17651 } 17830 17652 17831 - jsval_t len_key = js_mkstr(js, "length", 6); 17832 - js_setprop(js, result, len_key, tov((double) len)); 17833 17653 return mkval(T_ARR, vdata(result)); 17834 17654 } 17835 17655 ··· 17851 17671 jsval_t arr = js->this_val; 17852 17672 if (vtype(arr) != T_ARR) return js_mkerr(js, "toLocaleString called on non-array"); 17853 17673 17854 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17855 - jsoff_t len = 0; 17856 - if (len_off != 0) { 17857 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 17858 - if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 17859 - } 17674 + jsoff_t len = get_array_length(js, arr); 17860 17675 if (len == 0) return js_mkstr(js, "", 0); 17861 17676 17862 17677 char *result = NULL; ··· 17877 17692 result[result_len++] = ','; 17878 17693 } 17879 17694 17880 - char idx_str[16]; 17881 - snprintf(idx_str, sizeof(idx_str), "%u", (unsigned)i); 17882 - jsoff_t elem_off = lkp(js, arr, idx_str, strlen(idx_str)); 17883 - if (elem_off == 0) continue; 17884 - 17885 - jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17695 + if (!arr_has(js, arr, i)) continue; 17696 + jsval_t elem = arr_get(js, arr, i); 17886 17697 if (vtype(elem) == T_NULL || vtype(elem) == T_UNDEF) continue; 17887 17698 17888 17699 char buf[64]; ··· 17937 17748 jsoff_t str_len, str_off = vstr(js, src, &str_len); 17938 17749 const char *str_ptr = (const char *)&js->mem[str_off]; 17939 17750 for (jsoff_t i = 0; i < str_len; i++) { 17940 - char idxstr[16]; 17941 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17942 17751 jsval_t elem = js_mkstr(js, str_ptr + i, 1); 17943 17752 if (vtype(mapFn) == T_FUNC) { 17944 17753 jsval_t call_args[2] = { elem, tov((double)i) }; 17945 17754 elem = call_js_with_args(js, mapFn, call_args, 2); 17946 17755 if (is_err(elem)) return elem; 17947 17756 } 17948 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17949 - js_setprop(js, write_target, key, elem); 17757 + if (vtype(write_target) == T_ARR) arr_set(js, write_target, i, elem); 17758 + else { 17759 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17760 + js_setprop(js, write_target, js_mkstr(js, idxstr, idxlen), elem); 17761 + } 17950 17762 } 17951 - jsval_t len_key = js_mkstr(js, "length", 6); 17952 - js_setprop(js, result, len_key, tov((double) str_len)); 17763 + if (vtype(result) != T_ARR) { 17764 + jsval_t len_key = js_mkstr(js, "length", 6); 17765 + js_setprop(js, result, len_key, tov((double) str_len)); 17766 + } 17953 17767 } else if (vtype(src) == T_ARR || vtype(src) == T_OBJ) { 17954 - jsoff_t off = lkp_interned(js, src, INTERN_LENGTH, 6); 17955 - jsoff_t len = 0; 17956 - if (off != 0) { 17957 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17958 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17959 - } 17768 + jsoff_t len = get_array_length(js, src); 17960 17769 for (jsoff_t i = 0; i < len; i++) { 17961 - char idxstr[16]; 17962 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17963 - jsoff_t elem_off = lkp(js, src, idxstr, idxlen); 17964 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17770 + jsval_t elem = arr_get(js, src, i); 17965 17771 if (vtype(mapFn) == T_FUNC) { 17966 17772 jsval_t call_args[2] = { elem, tov((double)i) }; 17967 17773 elem = call_js_with_args(js, mapFn, call_args, 2); 17968 17774 if (is_err(elem)) return elem; 17969 17775 } 17970 - jsval_t key = js_mkstr(js, idxstr, idxlen); 17971 - js_setprop(js, write_target, key, elem); 17776 + if (vtype(write_target) == T_ARR) arr_set(js, write_target, i, elem); 17777 + else { 17778 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17779 + js_setprop(js, write_target, js_mkstr(js, idxstr, idxlen), elem); 17780 + } 17972 17781 } 17973 - jsval_t len_key = js_mkstr(js, "length", 6); 17974 - js_setprop(js, result, len_key, tov((double) len)); 17782 + if (vtype(result) != T_ARR) { 17783 + jsval_t len_key = js_mkstr(js, "length", 6); 17784 + js_setprop(js, result, len_key, tov((double) len)); 17785 + } 17975 17786 } 17976 17787 17977 17788 if (!use_ctor) return mkval(T_ARR, vdata(result)); ··· 17996 17807 jsval_t write_target = arr_is_proxy ? proxy_read_target(js, arr) : arr; 17997 17808 17998 17809 for (int i = 0; i < nargs; i++) { 17999 - char idxstr[16]; 18000 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 18001 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18002 - js_setprop(js, write_target, key, args[i]); 17810 + if (vtype(write_target) == T_ARR) arr_set(js, write_target, (jsoff_t)i, args[i]); 17811 + else { 17812 + char idxstr[16]; size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17813 + js_setprop(js, write_target, js_mkstr(js, idxstr, idxlen), args[i]); 17814 + } 17815 + } 17816 + if (vtype(arr) != T_ARR) { 17817 + jsval_t len_key = js_mkstr(js, "length", 6); 17818 + js_setprop(js, arr, len_key, tov((double) nargs)); 18003 17819 } 18004 - jsval_t len_key = js_mkstr(js, "length", 6); 18005 - js_setprop(js, arr, len_key, tov((double) nargs)); 18006 17820 18007 17821 if (!use_ctor) return mkval(T_ARR, vdata(arr)); 18008 17822 return arr; ··· 18119 17933 } 18120 17934 } 18121 17935 if (limit == 0) { 18122 - js_setprop(js, arr, js_mkstr(js, "length", 6), tov(0)); 18123 17936 return mkval(T_ARR, vdata(arr)); 18124 17937 } 18125 17938 if (nargs == 0) goto return_whole; ··· 18137 17950 if (plen == 0 || (plen == 4 && memcmp(pattern_ptr, "(?:)", 4) == 0)) { 18138 17951 jsoff_t idx = 0; 18139 17952 for (jsoff_t i = 0; i < str_len && idx < limit; i++) { 18140 - char idxstr[16]; 18141 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18142 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18143 17953 jsval_t part = js_mkstr(js, str_ptr + i, 1); 18144 - js_setprop(js, arr, key, part); 17954 + arr_set(js, arr, idx, part); 18145 17955 idx++; 18146 17956 } 18147 - jsval_t len_key = js_mkstr(js, "length", 6); 18148 - js_setprop(js, arr, len_key, tov((double)idx)); 18149 17957 return mkval(T_ARR, vdata(arr)); 18150 17958 } 18151 17959 ··· 18167 17975 if (rc >= 0) { 18168 17976 pcre2_match_data_free(match_data); 18169 17977 pcre2_code_free(re); 18170 - js_setprop(js, arr, js_mkstr(js, "length", 6), tov(0)); 18171 17978 return mkval(T_ARR, vdata(arr)); 18172 17979 } 18173 17980 } ··· 18209 18016 18210 18017 had_any_split = true; 18211 18018 18212 - char idxstr[16]; 18213 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18214 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18215 18019 jsval_t part = js_mkstr(js, str_ptr + segment_start, match_start - segment_start); 18216 - js_setprop(js, arr, key, part); 18020 + arr_set(js, arr, idx, part); 18217 18021 idx++; 18218 18022 18219 18023 for (uint32_t i = 1; i <= capture_count && idx < limit; i++) { 18220 18024 PCRE2_SIZE cap_start = ovector[2*i]; 18221 18025 PCRE2_SIZE cap_end = ovector[2*i+1]; 18222 - size_t cap_idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18223 - key = js_mkstr(js, idxstr, cap_idxlen); 18224 18026 if (cap_start == PCRE2_UNSET) { 18225 - js_setprop(js, arr, key, js_mkundef()); 18027 + arr_set(js, arr, idx, js_mkundef()); 18226 18028 } else { 18227 18029 part = js_mkstr(js, str_ptr + cap_start, cap_end - cap_start); 18228 - js_setprop(js, arr, key, part); 18030 + arr_set(js, arr, idx, part); 18229 18031 } 18230 18032 idx++; 18231 18033 } ··· 18242 18044 if (!had_any_split) { 18243 18045 pcre2_match_data_free(match_data); 18244 18046 pcre2_code_free(re); 18245 - js_setprop(js, arr, js_mkstr(js, "0", 1), js_mkstr(js, str_ptr, str_len)); 18246 - js_setprop(js, arr, js_mkstr(js, "length", 6), tov(1)); 18047 + arr_set(js, arr, 0, js_mkstr(js, str_ptr, str_len)); 18247 18048 return mkval(T_ARR, vdata(arr)); 18248 18049 } 18249 18050 18250 18051 if (idx < limit) { 18251 - char idxstr[16]; 18252 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18253 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18254 18052 jsval_t part = js_mkstr(js, str_ptr + segment_start, str_len - segment_start); 18255 - js_setprop(js, arr, key, part); 18053 + arr_set(js, arr, idx, part); 18256 18054 idx++; 18257 18055 } 18258 18056 18259 18057 pcre2_match_data_free(match_data); 18260 18058 pcre2_code_free(re); 18261 - jsval_t len_key = js_mkstr(js, "length", 6); 18262 - js_setprop(js, arr, len_key, tov((double)idx)); 18263 18059 return mkval(T_ARR, vdata(arr)); 18264 18060 } 18265 18061 ··· 18271 18067 18272 18068 if (sep_len == 0) { 18273 18069 for (jsoff_t i = 0; i < str_len && idx < limit; i++) { 18274 - char idxstr[16]; 18275 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18276 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18277 18070 jsval_t part = js_mkstr(js, str_ptr + i, 1); 18278 - js_setprop(js, arr, key, part); 18071 + arr_set(js, arr, idx, part); 18279 18072 idx++; 18280 18073 } 18281 - goto set_length; 18074 + return mkval(T_ARR, vdata(arr)); 18282 18075 } 18283 18076 18284 18077 for (jsoff_t i = 0; i + sep_len <= str_len && idx < limit; i++) { 18285 18078 if (memcmp(str_ptr + i, sep_ptr, sep_len) != 0) continue; 18286 - char idxstr[16]; 18287 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18288 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18289 18079 jsval_t part = js_mkstr(js, str_ptr + start, i - start); 18290 - js_setprop(js, arr, key, part); 18080 + arr_set(js, arr, idx, part); 18291 18081 idx++; 18292 18082 start = i + sep_len; 18293 18083 i += sep_len - 1; 18294 18084 } 18295 18085 if (idx < limit && start <= str_len) { 18296 - char idxstr[16]; 18297 - size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)idx); 18298 - jsval_t key = js_mkstr(js, idxstr, idxlen); 18299 18086 jsval_t part = js_mkstr(js, str_ptr + start, str_len - start); 18300 - js_setprop(js, arr, key, part); 18087 + arr_set(js, arr, idx, part); 18301 18088 idx++; 18302 18089 } 18303 18090 18304 - set_length:; 18305 - jsval_t len_key = js_mkstr(js, "length", 6); 18306 - js_setprop(js, arr, len_key, tov((double) idx)); 18307 18091 return mkval(T_ARR, vdata(arr)); 18308 18092 18309 18093 return_whole: 18310 18094 if (limit > 0) { 18311 - js_setprop(js, arr, js_mkstr(js, "0", 1), str); 18312 - js_setprop(js, arr, js_mkstr(js, "length", 6), tov(1)); 18313 - } else { 18314 - js_setprop(js, arr, js_mkstr(js, "length", 6), tov(0)); 18095 + arr_set(js, arr, 0, str); 18315 18096 } 18316 18097 return mkval(T_ARR, vdata(arr)); 18317 18098 } ··· 20429 20210 jsval_t value = nargs > 0 ? args[0] : js_mkundef(); 20430 20211 20431 20212 jsval_t results = js_get(js, tracker, "results"); 20432 - char idx[16]; 20433 - snprintf(idx, sizeof(idx), "%d", index); 20434 - js_setprop(js, results, js_mkstr(js, idx, strlen(idx)), value); 20213 + arr_set(js, results, (jsoff_t)index, value); 20435 20214 20436 20215 jsval_t remaining_val = js_get(js, tracker, "remaining"); 20437 20216 int remaining = (int)tod(remaining_val) - 1; ··· 20512 20291 if (is_err(iter_result)) return iter_result; 20513 20292 20514 20293 int len = ctx.index; 20515 - js_setprop(js, results, js_mkstr(js, "length", 6), tov((double)len)); 20294 + { 20295 + jsoff_t doff = get_dense_buf(js, results); 20296 + if (doff) { 20297 + if ((jsoff_t)len > dense_capacity(js, doff)) doff = dense_grow(js, results, (jsoff_t)len); 20298 + if (doff) dense_set_length(js, doff, (jsoff_t)len); 20299 + } 20300 + } 20516 20301 20517 20302 if (len == 0) { 20518 20303 jsval_t resolve_args[] = { mkval(T_ARR, vdata(results)) }; ··· 20611 20396 20612 20397 static void promise_any_record_rejection(struct js *js, jsval_t tracker, int index, jsval_t reason) { 20613 20398 jsval_t errors = resolveprop(js, js_get(js, tracker, "errors")); 20614 - char idx[16]; 20615 - snprintf(idx, sizeof(idx), "%d", index); 20616 - js_setprop(js, errors, js_mkstr(js, idx, strlen(idx)), reason); 20399 + arr_set(js, errors, (jsoff_t)index, reason); 20617 20400 20618 20401 int remaining = (int)tod(js_get(js, tracker, "remaining")) - 1; 20619 20402 js_set(js, tracker, "remaining", tov((double)remaining)); ··· 20642 20425 jsval_t arr = args[0]; 20643 20426 if (vtype(arr) != T_ARR) return js_mkerr(js, "Promise.any requires an array"); 20644 20427 20645 - jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 20646 - int len = len_off ? (int)tod(resolveprop(js, mkval(T_PROP, len_off))) : 0; 20428 + int len = (int)get_array_length(js, arr); 20647 20429 20648 20430 if (len == 0) { 20649 20431 jsval_t reject_args[] = { mk_aggregate_error(js, mkarr(js)) }; ··· 20659 20441 js_setprop(js, tracker, js_mkstr(js, "remaining", 9), tov((double)len)); 20660 20442 js_setprop(js, tracker, js_mkstr(js, "errors", 6), errors); 20661 20443 js_setprop(js, tracker, js_mkstr(js, "resolved", 8), js_false); 20662 - js_setprop(js, errors, js_mkstr(js, "length", 6), tov((double)len)); 20444 + 20445 + { 20446 + jsoff_t doff = get_dense_buf(js, errors); 20447 + if (doff) { 20448 + if ((jsoff_t)len > dense_capacity(js, doff)) doff = dense_grow(js, errors, (jsoff_t)len); 20449 + if (doff) dense_set_length(js, doff, (jsoff_t)len); 20450 + } 20451 + } 20663 20452 20664 20453 for (int i = 0; i < len; i++) { 20665 - char idx[16]; 20666 - snprintf(idx, sizeof(idx), "%d", i); 20667 - jsval_t item = resolveprop(js, js_get(js, arr, idx)); 20454 + jsval_t item = arr_get(js, arr, (jsoff_t)i); 20455 + item = resolveprop(js, item); 20668 20456 20669 20457 if (vtype(item) != T_PROMISE) { 20670 20458 promise_any_try_resolve(js, tracker, item); ··· 20824 20612 return js_bool(js_truthy(js, result)); 20825 20613 } 20826 20614 20615 + if (vtype(r) == T_ARR) { 20616 + unsigned long idx; 20617 + jsoff_t arr_len = get_array_length(js, r); 20618 + if (parse_array_index(prop_name, prop_len, arr_len, &idx)) { 20619 + return mkval(T_BOOL, arr_has(js, r, (jsoff_t)idx) ? 1 : 0); 20620 + } 20621 + if (prop_len == 6 && memcmp(prop_name, "length", 6) == 0) { 20622 + return mkval(T_BOOL, 1); 20623 + } 20624 + } 20625 + 20827 20626 jsoff_t found = lkp_proto(js, r, prop_name, prop_len); 20828 20627 return mkval(T_BOOL, found != 0 ? 1 : 0); 20829 20628 } ··· 21100 20899 jsval_t data_arr = mkarr(js); 21101 20900 21102 20901 for (size_t i = 0; i < size; i++) { 21103 - char idx[16]; 21104 - snprintf(idx, sizeof(idx), "%zu", i); 21105 - js_setprop(js, data_arr, js_mkstr(js, idx, strlen(idx)), tov((double)content[i])); 20902 + arr_set(js, data_arr, (jsoff_t)i, tov((double)content[i])); 21106 20903 } 21107 - js_setprop(js, data_arr, js_mkstr(js, "length", 6), tov((double)size)); 21108 20904 21109 20905 js_setprop(js, obj, js_mkstr(js, "data", 4), mkval(T_ARR, vdata(data_arr))); 21110 20906 js_setprop(js, obj, js_mkstr(js, "path", 4), js_mkstr(js, path, strlen(path))); ··· 21819 21615 21820 21616 static jsoff_t proxy_aware_length(struct js *js, jsval_t obj) { 21821 21617 jsval_t src = is_proxy(js, obj) ? proxy_read_target(js, obj) : obj; 21618 + if (vtype(src) == T_ARR) { 21619 + jsoff_t doff = get_dense_buf(js, src); 21620 + if (doff) return dense_length(js, doff); 21621 + } 21822 21622 jsoff_t off = lkp_interned(js, src, INTERN_LENGTH, 6); 21823 21623 if (off == 0) return 0; 21824 21624 jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); ··· 22736 22536 } 22737 22537 22738 22538 if (vtype(obj) == T_ARR) { 22539 + if (key_len == 6 && memcmp(key, "length", 6) == 0) { 22540 + *out = tov((double)get_array_length(js, obj)); 22541 + return true; 22542 + } 22543 + unsigned long idx; 22544 + jsoff_t arr_len = get_array_length(js, obj); 22545 + if (parse_array_index(key, key_len, arr_len, &idx)) { 22546 + if (arr_has(js, obj, (jsoff_t)idx)) { 22547 + *out = arr_get(js, obj, (jsoff_t)idx); 22548 + return true; 22549 + } return false; 22550 + } 22739 22551 jsval_t arr_obj = mkval(T_OBJ, vdata(obj)); 22740 22552 jsoff_t off = lkp(js, arr_obj, key, key_len); 22741 22553 if (off == 0) return false;
+34 -2
src/gc.c
··· 415 415 } 416 416 417 417 jsval_t val = gc_loadval(ctx->js->mem, old_off + sizeof(jsoff_t) + sizeof(jsoff_t)); 418 - jsval_t new_val = gc_update_val(ctx, val); 419 - gc_saveval(ctx->new_mem, new_off + sizeof(jsoff_t) + sizeof(jsoff_t), new_val); 418 + if (!is_slot) goto update_val; 419 + 420 + jsoff_t slot_id = gc_loadoff(ctx->js->mem, old_off + sizeof(jsoff_t)); 421 + if (slot_id != (jsoff_t)SLOT_DENSE_BUF) goto update_val; 422 + 423 + jsoff_t old_doff = (jsoff_t)tod(val); 424 + if (old_doff == 0 || old_doff >= ctx->js->brk) goto update_val; 425 + 426 + jsoff_t cap = gc_loadoff(ctx->js->mem, old_doff); 427 + jsoff_t len = gc_loadoff(ctx->js->mem, old_doff + sizeof(jsoff_t)); 428 + jsoff_t buf_size = (jsoff_t)(sizeof(jsoff_t) * 2 + sizeof(jsval_t) * cap); 429 + jsoff_t new_doff = gc_alloc(ctx, buf_size); 430 + if (new_doff == (jsoff_t)~0) goto update_val; 431 + 432 + memcpy(&ctx->new_mem[new_doff], &ctx->js->mem[old_doff], buf_size); 433 + for (jsoff_t i = 0; i < len; i++) { 434 + jsoff_t voff = new_doff + (jsoff_t)(sizeof(jsoff_t) * 2 + sizeof(jsval_t) * i); 435 + jsval_t v = gc_loadval(ctx->new_mem, voff); 436 + if (v != T_EMPTY) { 437 + jsval_t nv = gc_update_val(ctx, v); 438 + gc_saveval(ctx->new_mem, voff, nv); 439 + } 440 + } 441 + 442 + gc_saveval( 443 + ctx->new_mem, 444 + new_off + sizeof(jsoff_t) + sizeof(jsoff_t), 445 + tov((double)new_doff) 446 + ); return; 447 + 448 + update_val: { 449 + jsval_t new_val = gc_update_val(ctx, val); 450 + gc_saveval(ctx->new_mem, new_off + sizeof(jsoff_t) + sizeof(jsoff_t), new_val); 451 + } 420 452 } 421 453 422 454 static void gc_process_object(gc_ctx_t *ctx, jsoff_t old_off) {
+177
tests/bench_dense.js
··· 1 + const now = () => typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now(); 2 + 3 + function bench(name, fn, iters = 1) { 4 + // warmup 5 + fn(); 6 + const t0 = now(); 7 + for (let i = 0; i < iters; i++) fn(); 8 + const dt = now() - t0; 9 + const per = (dt / iters).toFixed(3); 10 + console.log(`${name}: ${dt.toFixed(2)} ms total, ${per} ms/iter (${iters} iters)`); 11 + } 12 + 13 + // ------------------------------------------------------- 14 + // 1. Sequential push โ€” O(n) lkp per push makes this O(nยฒ) 15 + // ------------------------------------------------------- 16 + function push_n(n) { 17 + const arr = []; 18 + for (let i = 0; i < n; i++) arr.push(i); 19 + return arr; 20 + } 21 + 22 + bench('push 1k', () => push_n(1000), 100); 23 + bench('push 5k', () => push_n(5000), 20); 24 + bench('push 10k', () => push_n(10000), 5); 25 + 26 + // ------------------------------------------------------- 27 + // 2. Index write โ€” arr[i] = v walks property chain 28 + // ------------------------------------------------------- 29 + function index_write(n) { 30 + const arr = []; 31 + for (let i = 0; i < n; i++) arr[i] = i; 32 + return arr; 33 + } 34 + 35 + bench('index write 1k', () => index_write(1000), 100); 36 + bench('index write 5k', () => index_write(5000), 20); 37 + 38 + // ------------------------------------------------------- 39 + // 3. Index read โ€” arr[i] walks property chain from head 40 + // ------------------------------------------------------- 41 + function index_read(arr, n) { 42 + let sum = 0; 43 + for (let i = 0; i < n; i++) sum += arr[i]; 44 + return sum; 45 + } 46 + 47 + { 48 + const arr1k = push_n(1000); 49 + bench('index read 1k', () => index_read(arr1k, 1000), 200); 50 + } 51 + { 52 + const arr5k = push_n(5000); 53 + bench('index read 5k', () => index_read(arr5k, 5000), 20); 54 + } 55 + 56 + // ------------------------------------------------------- 57 + // 4. Random access โ€” worst case for linked property chain 58 + // ------------------------------------------------------- 59 + function random_read(arr, indices) { 60 + let sum = 0; 61 + for (let i = 0; i < indices.length; i++) sum += arr[indices[i]]; 62 + return sum; 63 + } 64 + 65 + { 66 + const n = 2000; 67 + const arr = push_n(n); 68 + const indices = []; 69 + let s = 7; 70 + for (let i = 0; i < n; i++) { 71 + s = (s * 1103515245 + 12345) & 0x7fffffff; 72 + indices.push(s % n); 73 + } 74 + bench('random read 2k', () => random_read(arr, indices), 50); 75 + } 76 + 77 + // ------------------------------------------------------- 78 + // 5. Pop โ€” must walk chain to find last element 79 + // ------------------------------------------------------- 80 + function push_then_pop(n) { 81 + const arr = []; 82 + for (let i = 0; i < n; i++) arr.push(i); 83 + for (let i = 0; i < n; i++) arr.pop(); 84 + } 85 + 86 + bench('push+pop 1k', () => push_then_pop(1000), 50); 87 + 88 + // ------------------------------------------------------- 89 + // 6. Iteration โ€” forEach / map / filter / reduce 90 + // ------------------------------------------------------- 91 + { 92 + const arr1k = push_n(1000); 93 + 94 + bench('forEach 1k', () => { 95 + let s = 0; 96 + arr1k.forEach(x => s += x); 97 + }, 200); 98 + 99 + bench('map 1k', () => arr1k.map(x => x * 2), 100); 100 + bench('filter 1k', () => arr1k.filter(x => x % 2 === 0), 100); 101 + bench('reduce 1k', () => arr1k.reduce((a, b) => a + b, 0), 200); 102 + } 103 + 104 + // ------------------------------------------------------- 105 + // 7. Slice / concat / spread 106 + // ------------------------------------------------------- 107 + { 108 + const arr1k = push_n(1000); 109 + bench('slice 1k', () => arr1k.slice(), 100); 110 + bench('concat 1k', () => arr1k.concat(arr1k), 50); 111 + bench('spread 1k', () => [...arr1k], 100); 112 + } 113 + 114 + // ------------------------------------------------------- 115 + // 8. Sort โ€” reads + writes every element 116 + // ------------------------------------------------------- 117 + { 118 + function make_random_arr(n) { 119 + const arr = []; 120 + let s = 42; 121 + for (let i = 0; i < n; i++) { 122 + s = (s * 1103515245 + 12345) & 0x7fffffff; 123 + arr.push(s % 10000); 124 + } 125 + return arr; 126 + } 127 + bench('sort 500', () => make_random_arr(500).sort((a, b) => a - b), 20); 128 + } 129 + 130 + // ------------------------------------------------------- 131 + // 9. Reverse 132 + // ------------------------------------------------------- 133 + { 134 + const arr = push_n(1000); 135 + bench('reverse 1k', () => { 136 + arr.reverse(); 137 + }, 100); 138 + } 139 + 140 + // ------------------------------------------------------- 141 + // 10. Array.from / entries / keys / values 142 + // ------------------------------------------------------- 143 + { 144 + const arr = push_n(500); 145 + bench('Array.from 500', () => Array.from(arr), 50); 146 + bench('entries 500', () => arr.entries(), 50); 147 + bench('keys 500', () => arr.keys(), 50); 148 + bench('values 500', () => arr.values(), 50); 149 + } 150 + 151 + // ------------------------------------------------------- 152 + // 11. JSON.stringify โ€” must iterate all elements 153 + // ------------------------------------------------------- 154 + { 155 + const arr = push_n(500); 156 + bench('JSON.stringify 500', () => JSON.stringify(arr), 50); 157 + } 158 + 159 + // ------------------------------------------------------- 160 + // 12. Scaling test โ€” show O(nยฒ) behavior 161 + // ------------------------------------------------------- 162 + console.log('\n--- scaling (push N, expect ~linear with dense) ---'); 163 + for (const n of [500, 1000, 2000, 4000]) { 164 + const t0 = now(); 165 + push_n(n); 166 + const dt = now() - t0; 167 + console.log(`push ${n}: ${dt.toFixed(2)} ms`); 168 + } 169 + 170 + console.log('\n--- scaling (sequential read N, expect ~linear with dense) ---'); 171 + for (const n of [500, 1000, 2000, 4000]) { 172 + const arr = push_n(n); 173 + const t0 = now(); 174 + index_read(arr, n); 175 + const dt = now() - t0; 176 + console.log(`read ${n}: ${dt.toFixed(2)} ms`); 177 + }