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.

optimize array property handling

+412 -109
+2
.gitignore
··· 2 2 .nova 3 3 .maid 4 4 .cache 5 + 6 + .claude 5 7 .github/artifacts 6 8 7 9 *.so
+1 -1
examples/test262/index.js
··· 223 223 } 224 224 225 225 lines.push(''); 226 - lines.push(`${c.dim}m browse ยท g gc ยท q quit${c.reset}`); 226 + lines.push(`${c.dim}m browse ยท g gc ยท q quit${c.reset} ${c.cyan}${fps.current} fps${c.reset}`); 227 227 } 228 228 229 229 return lines.map(l => pad(l, cols)).join('\n');
+350 -108
src/ant.c
··· 1082 1082 return count <= 4 && !has_nested; 1083 1083 } 1084 1084 1085 - static bool is_array_index(const char *key, jsoff_t klen) { 1086 - if (klen == 0) return false; 1085 + static inline bool is_array_index(const char *key, jsoff_t klen) { 1086 + if (klen == 0 || (klen > 1 && key[0] == '0')) return false; 1087 1087 for (jsoff_t i = 0; i < klen; i++) { 1088 1088 if (key[i] < '0' || key[i] > '9') return false; 1089 1089 } 1090 + return true; 1091 + } 1092 + 1093 + static inline bool parse_array_index(const char *key, size_t klen, jsoff_t max_len, unsigned long *out_idx) { 1094 + if (klen == 0 || key[0] < '0' || key[0] > '9') return false; 1095 + unsigned long parsed_idx = 0; 1096 + 1097 + for (size_t i = 0; i < klen; i++) { 1098 + if (key[i] < '0' || key[i] > '9') return false; 1099 + parsed_idx = parsed_idx * 10 + (key[i] - '0'); 1100 + } 1101 + 1102 + if (parsed_idx >= max_len) return false; 1103 + *out_idx = parsed_idx; 1090 1104 return true; 1091 1105 } 1092 1106 ··· 3288 3302 return js_mkundef(); 3289 3303 } 3290 3304 3305 + static inline jsval_t check_object_extensibility(struct js *js, jsval_t obj) { 3306 + jsoff_t obj_off_fp = (jsoff_t)vdata(obj); 3307 + jsoff_t next = loadoff(js, obj_off_fp) & ~(3U | FLAGMASK); 3308 + 3309 + while (next != 0 && next < js->brk) { 3310 + jsoff_t hdr = loadoff(js, next); 3311 + if ((hdr & SLOTMASK) == 0) break; 3312 + 3313 + jsoff_t sk = loadoff(js, next + sizeof(jsoff_t)); 3314 + jsval_t sv = loadval(js, next + sizeof(jsoff_t) * 2); 3315 + 3316 + if (sk == (jsoff_t)SLOT_FROZEN && js_truthy(js, sv)) { 3317 + return (js->flags & F_STRICT) 3318 + ? js_mkerr(js, "cannot add property to frozen object") 3319 + : js_mkundef(); 3320 + } 3321 + 3322 + if (sk == (jsoff_t)SLOT_SEALED && js_truthy(js, sv)) { 3323 + return (js->flags & F_STRICT) 3324 + ? js_mkerr(js, "cannot add property to sealed object") 3325 + : js_mkundef(); 3326 + } 3327 + 3328 + if (sk == (jsoff_t)SLOT_EXTENSIBLE && !js_truthy(js, sv)) { 3329 + return (js->flags & F_STRICT) 3330 + ? js_mkerr(js, "cannot add property to non-extensible object") 3331 + : js_mkundef(); 3332 + } 3333 + 3334 + next = hdr & ~(3U | FLAGMASK); 3335 + } 3336 + 3337 + return js_mkundef(); 3338 + } 3339 + 3340 + static inline void update_array_length(struct js *js, jsval_t obj, jsoff_t new_len) { 3341 + jsoff_t len_off = lkp_interned(js, obj, INTERN_LENGTH, 6); 3342 + jsval_t new_len_val = tov((double)new_len); 3343 + 3344 + if (len_off != 0) saveval(js, len_off + sizeof(jsoff_t) * 2, new_len_val); 3345 + else js_mkprop_fast(js, obj, "length", 6, new_len_val); 3346 + } 3347 + 3348 + static jsval_t js_setprop_array_fast(struct js *js, jsval_t obj, jsval_t k, jsval_t v, jsoff_t klen, const char *key) { 3349 + unsigned long idx; 3350 + if (!parse_array_index(key, klen, (jsoff_t)-1, &idx)) return js_mkundef(); 3351 + 3352 + jsoff_t cur_len = get_array_length(js, obj); 3353 + if (idx < cur_len) return js_mkundef(); 3354 + 3355 + jsval_t extensibility_error = check_object_extensibility(js, obj); 3356 + if (!is_undefined(extensibility_error)) return extensibility_error; 3357 + 3358 + jsval_t result = mkprop_fast(js, obj, k, v, 0); 3359 + update_array_length(js, obj, idx + 1); 3360 + 3361 + return result; 3362 + } 3363 + 3291 3364 jsval_t js_setprop(struct js *js, jsval_t obj, jsval_t k, jsval_t v) { 3292 3365 jsoff_t klen; jsoff_t koff = vstr(js, k, &klen); 3293 3366 const char *key = (char *) &js->mem[koff]; 3294 3367 3368 + if (vtype(obj) == T_ARR && !is_proxy(js, obj) && klen > 0 && key[0] >= '0' && key[0] <= '9') { 3369 + jsval_t result = js_setprop_array_fast(js, obj, k, v, klen, key); 3370 + if (vtype(result) != T_UNDEF) return result; 3371 + } 3372 + 3295 3373 if (vtype(obj) == T_ARR && streq(key, klen, "length", 6)) { 3296 3374 jsval_t err = validate_array_length(js, v); 3297 3375 if (is_err(err)) return err; ··· 3303 3381 return v; 3304 3382 } 3305 3383 3306 - if (try_dynamic_setter(js, obj, key, klen, v)) { 3307 - return v; 3308 - } 3309 - 3384 + if (try_dynamic_setter(js, obj, key, klen, v)) return v; 3310 3385 jsoff_t existing = lkp(js, obj, key, klen); 3311 3386 3312 3387 { ··· 5432 5507 return false; 5433 5508 } 5434 5509 5435 - jsval_t resolveprop(struct js *js, jsval_t v) { 5436 - if (vtype(v) == T_PROPREF) { 5437 - if (is_prim_propref(v)) { 5438 - prim_propref_data_t *prim_data = prim_propref_get(v); 5439 - if (!prim_data) return js_mkundef(); 5440 - 5441 - jsval_t prim = prim_data->prim_val; 5442 - jsval_t key = mkval(T_STR, prim_data->key_off); 5443 - jsoff_t key_len; 5444 - const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 5445 - 5446 - jsval_t proto = get_prototype_for_type(js, vtype(prim)); 5447 - if (vtype(proto) == T_OBJ) { 5448 - jsval_t getter = js_mkundef(); 5449 - bool has_getter = false; 5450 - lkp_with_getter(js, proto, key_str, key_len, &getter, &has_getter); 5451 - jsval_t result = call_proto_accessor(js, prim, getter, has_getter, NULL, 0, false); 5452 - if (vtype(result) != T_UNDEF) return result; 5510 + static inline jsval_t resolve_array_length(struct js *js, jsoff_t obj_off) { 5511 + jsval_t arr = mkval(T_ARR, obj_off); 5512 + return tov(D(get_array_length(js, arr))); 5513 + } 5514 + 5515 + static inline jsval_t resolve_array_index_prop(struct js *js, jsoff_t obj_off, const char *key_str, jsoff_t len) { 5516 + jsval_t arr = mkval(T_ARR, obj_off); 5517 + jsoff_t prop_off = lkp(js, arr, key_str, len); 5518 + if (prop_off != 0) return resolveprop(js, mkval(T_PROP, prop_off)); 5519 + return js_mkundef(); 5520 + } 5521 + 5522 + static inline jsval_t resolve_prim_propref(struct js *js, jsval_t v) { 5523 + prim_propref_data_t *prim_data = prim_propref_get(v); 5524 + if (!prim_data) return js_mkundef(); 5525 + 5526 + jsval_t prim = prim_data->prim_val; 5527 + jsval_t key = mkval(T_STR, prim_data->key_off); 5528 + jsoff_t key_len; const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 5529 + 5530 + jsval_t proto = get_prototype_for_type(js, vtype(prim)); 5531 + if (vtype(proto) == T_OBJ) { 5532 + jsval_t getter = js_mkundef(); 5533 + bool has_getter = false; 5534 + lkp_with_getter(js, proto, key_str, key_len, &getter, &has_getter); 5535 + jsval_t result = call_proto_accessor(js, prim, getter, has_getter, NULL, 0, false); 5536 + if (vtype(result) != T_UNDEF) return result; 5537 + 5538 + jsoff_t off = lkp_proto(js, prim, key_str, key_len); 5539 + if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 5540 + } 5541 + 5542 + return js_mkundef(); 5543 + } 5453 5544 5454 - jsoff_t off = lkp_proto(js, prim, key_str, key_len); 5455 - if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 5456 - } 5457 - 5458 - return js_mkundef(); 5545 + static inline jsval_t resolve_array_named_prop(struct js *js, jsoff_t obj_off, const char *key_str, jsoff_t len) { 5546 + jsval_t obj = mkval(T_ARR, obj_off); 5547 + 5548 + if (len == STR_PROTO_LEN && memcmp(key_str, STR_PROTO, STR_PROTO_LEN) == 0) { 5549 + jsval_t proto = get_slot(js, obj, SLOT_PROTO); 5550 + if (vtype(proto) != T_UNDEF) return proto; 5551 + return get_prototype_for_type(js, T_ARR); 5552 + } 5553 + 5554 + jsval_t proto = get_slot(js, obj, SLOT_PROTO); 5555 + if (vtype(proto) == T_UNDEF || vtype(proto) == T_NULL) { 5556 + proto = get_prototype_for_type(js, T_ARR); 5557 + } 5558 + 5559 + if (is_object_type(proto)) { 5560 + const char *key_intern = intern_string(key_str, len); 5561 + if (key_intern) { 5562 + jsoff_t off = lkp_interned(js, proto, key_intern, len); 5563 + if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 5459 5564 } 5460 5565 5566 + jsoff_t proto_off = lkp_proto(js, proto, key_str, len); 5567 + if (proto_off != 0) return resolveprop(js, mkval(T_PROP, proto_off)); 5568 + } 5569 + 5570 + jsoff_t prop_off = lkp(js, obj, key_str, len); 5571 + if (prop_off != 0) return resolveprop(js, mkval(T_PROP, prop_off)); 5572 + 5573 + jsval_t dyn_result = try_dynamic_getter(js, obj, key_str, len); 5574 + if (vtype(dyn_result) != T_UNDEF) return dyn_result; 5575 + 5576 + return js_mkundef(); 5577 + } 5578 + 5579 + static inline jsval_t resolve_object_prop(struct js *js, jsval_t obj, const char *key_str, jsoff_t len) { 5580 + if (is_proxy(js, obj)) return proxy_get(js, obj, key_str, len); 5581 + 5582 + if (len == STR_PROTO_LEN && memcmp(key_str, STR_PROTO, STR_PROTO_LEN) == 0) { 5583 + jsval_t proto = get_slot(js, obj, SLOT_PROTO); 5584 + if (vtype(proto) != T_UNDEF) return proto; 5585 + return get_prototype_for_type(js, vtype(obj)); 5586 + } 5587 + 5588 + jsoff_t prop_off = lkp(js, obj, key_str, len); 5589 + if (prop_off != 0) return resolveprop(js, mkval(T_PROP, prop_off)); 5590 + 5591 + jsoff_t proto_off = lkp_proto(js, obj, key_str, len); 5592 + if (proto_off != 0) return resolveprop(js, mkval(T_PROP, proto_off)); 5593 + 5594 + jsval_t accessor_result; 5595 + if (try_accessor_getter(js, obj, key_str, len, &accessor_result)) { 5596 + return accessor_result; 5597 + } 5598 + 5599 + jsval_t dyn_result = try_dynamic_getter(js, obj, key_str, len); 5600 + if (vtype(dyn_result) != T_UNDEF) return dyn_result; 5601 + 5602 + return js_mkundef(); 5603 + } 5604 + 5605 + jsval_t resolveprop(struct js *js, jsval_t v) { 5606 + if (vtype(v) == T_PROPREF) { 5607 + if (is_prim_propref(v)) return resolve_prim_propref(js, v); 5608 + 5461 5609 jsoff_t obj_off = propref_obj(v); 5462 5610 jsoff_t key_off = propref_key(v); 5463 5611 jsval_t key = mkval(T_STR, key_off); 5464 - jsoff_t len; 5465 - const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 5466 5612 5467 - if (is_arr_off(js, obj_off) && streq(key_str, len, "length", 6)) { 5468 - jsval_t arr = mkval(T_ARR, obj_off); 5469 - return tov(D(js_arr_len(js, arr))); 5470 - } 5471 - 5472 - uint8_t obj_type = is_arr_off(js, obj_off) ? T_ARR : (is_func_off(js, obj_off) ? T_FUNC : T_OBJ); 5473 - jsval_t obj = mkval(obj_type, obj_off); 5474 - if (is_proxy(js, obj)) return proxy_get(js, obj, key_str, len); 5475 - 5476 - if (len == STR_PROTO_LEN && memcmp(key_str, STR_PROTO, STR_PROTO_LEN) == 0) { 5477 - jsval_t proto = get_slot(js, obj, SLOT_PROTO); 5478 - if (vtype(proto) != T_UNDEF) return proto; 5479 - return get_prototype_for_type(js, vtype(obj)); 5613 + jsoff_t len; const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 5614 + if (is_arr_off(js, obj_off) && streq(key_str, len, "length", 6)) return resolve_array_length(js, obj_off); 5615 + 5616 + if (is_arr_off(js, obj_off) && len > 0 && key_str[0] >= '0' && key_str[0] <= '9') { 5617 + if (is_array_index(key_str, len)) return resolve_array_index_prop(js, obj_off, key_str, len); 5480 5618 } 5481 - 5482 - jsoff_t prop_off = lkp(js, obj, key_str, len); 5483 - if (prop_off != 0) return resolveprop(js, mkval(T_PROP, prop_off)); 5484 - 5485 - jsoff_t proto_off = lkp_proto(js, obj, key_str, len); 5486 - if (proto_off != 0) return resolveprop(js, mkval(T_PROP, proto_off)); 5487 - 5488 - jsval_t accessor_result; 5489 - if (try_accessor_getter(js, obj, key_str, len, &accessor_result)) { 5490 - return accessor_result; 5619 + 5620 + if (is_arr_off(js, obj_off) && len > 0 && (key_str[0] < '0' || key_str[0] > '9')) { 5621 + return resolve_array_named_prop(js, obj_off, key_str, len); 5491 5622 } 5492 - 5493 - jsval_t dyn_result = try_dynamic_getter(js, obj, key_str, len); 5494 - if (vtype(dyn_result) != T_UNDEF) return dyn_result; 5623 + 5624 + uint8_t obj_type = is_arr_off(js, obj_off) 5625 + ? T_ARR : (is_func_off(js, obj_off) ? T_FUNC : T_OBJ); 5495 5626 5496 - return js_mkundef(); 5627 + jsval_t obj = mkval(obj_type, obj_off); 5628 + return resolve_object_prop(js, obj, key_str, len); 5497 5629 } 5630 + 5498 5631 if (vtype(v) != T_PROP) return v; 5499 5632 return resolveprop(js, loadval(js, (jsoff_t) (vdata(v) + sizeof(jsoff_t) * 2))); 5500 5633 } ··· 5516 5649 return true; 5517 5650 } 5518 5651 5652 + static jsval_t assign_array_index_fast( 5653 + struct js *js, jsval_t obj, 5654 + jsoff_t obj_off, jsval_t key, 5655 + const char *key_str, 5656 + jsoff_t key_len, jsval_t val 5657 + ) { 5658 + int is_numeric = 1; 5659 + unsigned long idx = 0; 5660 + for (jsoff_t ci = 0; ci < key_len; ci++) { 5661 + if (key_str[ci] < '0' || key_str[ci] > '9') { is_numeric = 0; break; } 5662 + idx = idx * 10 + (key_str[ci] - '0'); 5663 + } 5664 + 5665 + if (!is_numeric || (key_len > 1 && key_str[0] == '0')) return js_mkundef(); 5666 + int known_new = 0; jsoff_t tail = loadoff(js, obj_off + sizeof(jsoff_t) * 2); 5667 + 5668 + if (tail != 0 && tail < js->brk) { 5669 + jsoff_t tail_koff = loadoff(js, tail + sizeof(jsoff_t)); 5670 + jsoff_t tail_klen = offtolen(loadoff(js, tail_koff)); 5671 + const char *tail_key = (char *)&js->mem[tail_koff + sizeof(jsoff_t)]; 5672 + if (tail_klen > 0 && tail_key[0] >= '0' && tail_key[0] <= '9') { 5673 + unsigned long tail_idx = 0; 5674 + int tail_valid = 1; 5675 + for (jsoff_t ci = 0; ci < tail_klen; ci++) { 5676 + if (tail_key[ci] < '0' || tail_key[ci] > '9') { tail_valid = 0; break; } 5677 + tail_idx = tail_idx * 10 + (tail_key[ci] - '0'); 5678 + } 5679 + if (tail_valid && idx > tail_idx) known_new = 1; 5680 + } 5681 + } 5682 + 5683 + jsoff_t existing = 0; 5684 + if (!known_new) { 5685 + const char *interned = intern_string(key_str, key_len); 5686 + existing = interned ? lkp_interned(js, obj, interned, key_len) : 0; 5687 + } 5688 + 5689 + if (existing != 0) { 5690 + saveval(js, existing + sizeof(jsoff_t) * 2, val); 5691 + } else { 5692 + mkprop_fast(js, obj, key, val, 0); 5693 + jsoff_t len_off = lkp_interned(js, obj, INTERN_LENGTH, 6); 5694 + jsoff_t cur_len = 0; 5695 + if (len_off != 0) { 5696 + jsval_t lv = resolveprop(js, mkval(T_PROP, len_off)); 5697 + if (vtype(lv) == T_NUM) cur_len = (jsoff_t) tod(lv); 5698 + } 5699 + if (idx >= cur_len) { 5700 + jsval_t new_len = tov((double)(idx + 1)); 5701 + if (len_off != 0) saveval(js, len_off + sizeof(jsoff_t) * 2, new_len); 5702 + else js_mkprop_fast(js, obj, "length", 6, new_len); 5703 + } 5704 + } 5705 + 5706 + return val; 5707 + } 5708 + 5519 5709 static jsval_t assign(struct js *js, jsval_t lhs, jsval_t val) { 5520 5710 if (js->flags & F_NOEXEC) return val; 5521 5711 if (vtype(lhs) == T_PROPREF) { ··· 5553 5743 jsoff_t key_off = propref_key(lhs); 5554 5744 jsval_t obj = mkval(is_arr_off(js, obj_off) ? T_ARR : T_OBJ, obj_off); 5555 5745 jsval_t key = mkval(T_STR, key_off); 5556 - 5746 + 5557 5747 jsoff_t key_len; 5558 5748 const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 5559 5749 5750 + if (vtype(obj) == T_ARR && !is_proxy(js, obj) && key_len > 0 && key_str[0] >= '0' && key_str[0] <= '9') { 5751 + jsval_t result = assign_array_index_fast(js, obj, obj_off, key, key_str, key_len, val); 5752 + if (vtype(result) != T_UNDEF) return result; 5753 + } 5754 + 5560 5755 jsval_t setter_result; 5561 5756 if (try_accessor_setter(js, obj, key_str, key_len, val, &setter_result)) { 5562 5757 return setter_result; 5563 - } 5564 - 5565 - return js_setprop(js, obj, key, val); 5758 + } return js_setprop(js, obj, key, val); 5566 5759 } 5567 5760 5568 5761 if (vtype(lhs) != T_PROP) { ··· 5837 6030 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR) { 5838 6031 return js_mkundef(); 5839 6032 } 6033 + if (vtype(obj) == T_ARR && !is_proxy(js, obj) && keylen > 0 && keystr[0] >= '0' && keystr[0] <= '9') { 6034 + int valid = 1; 6035 + for (size_t ci = 0; ci < keylen; ci++) { 6036 + if (keystr[ci] < '0' || keystr[ci] > '9') { valid = 0; break; } 6037 + } 6038 + if (valid && (keylen == 1 || keystr[0] != '0')) { 6039 + jsval_t key = js_mkstr(js, keystr, keylen); 6040 + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 6041 + } 6042 + } 6043 + 5840 6044 if ((streq(keystr, keylen, "callee", 6) || streq(keystr, keylen, "caller", 6)) && 5841 6045 vtype(get_slot(js, obj, SLOT_STRICT_ARGS)) != T_UNDEF) { 5842 6046 return js_mkerr_typed(js, JS_ERR_TYPE, "'%.*s' not allowed on strict arguments", (int)keylen, keystr); ··· 5999 6203 } 6000 6204 6001 6205 if (plen == STR_PROTO_LEN && memcmp(ptr, STR_PROTO, STR_PROTO_LEN) == 0) { 6206 + jsval_t key = js_mkstr(js, ptr, plen); 6207 + return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 6208 + } 6209 + 6210 + if (t == T_ARR && !is_proxy(js, l) && plen > 0 && (ptr[0] < '0' || ptr[0] > '9')) { 6211 + jsoff_t obj_off = (jsoff_t)vdata(l); 6212 + descriptor_entry_t *desc = lookup_descriptor(obj_off, ptr, plen); 6213 + if (desc) { 6214 + jsval_t key = js_mkstr(js, ptr, plen); 6215 + return mkpropref(obj_off, (jsoff_t)vdata(key)); 6216 + } 6217 + jsval_t result = try_dynamic_getter(js, l, ptr, plen); 6218 + if (vtype(result) != T_UNDEF) { 6219 + jsoff_t own_off = lkp(js, l, ptr, plen); 6220 + if (own_off != 0) return mkval(T_PROP, own_off); 6221 + } 6002 6222 jsval_t key = js_mkstr(js, ptr, plen); 6003 6223 return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 6004 6224 } ··· 15829 16049 return js_call_toString(js, js->this_val); 15830 16050 } 15831 16051 15832 - static inline bool parse_array_index(const char *key, size_t key_len, jsoff_t len, unsigned *out_idx) { 15833 - if (key_len == 0 || key[0] > '9' || key[0] < '0') return false; 15834 - unsigned parsed_idx = 0; 15835 - for (size_t i = 0; i < key_len; i++) { 15836 - if (key[i] < '0' || key[i] > '9') return false; 15837 - parsed_idx = parsed_idx * 10 + (key[i] - '0'); 15838 - } 15839 - if (parsed_idx >= len) return false; 15840 - *out_idx = parsed_idx; 15841 - return true; 15842 - } 15843 - 15844 16052 static inline bool is_callable(jsval_t v) { 15845 16053 uint8_t t = vtype(v); 15846 16054 return t == T_FUNC || t == T_CFUNC; ··· 15878 16086 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 15879 16087 return js_mkerr(js, "push called on non-array"); 15880 16088 } 15881 - 16089 + 16090 + if (is_proxy(js, arr)) { 16091 + jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16092 + jsoff_t len = 0; 16093 + if (off != 0) { 16094 + jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16095 + if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16096 + } 16097 + for (int i = 0; i < nargs; i++) { 16098 + char idxstr[16]; 16099 + size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); 16100 + jsval_t key = js_mkstr(js, idxstr, idxlen); 16101 + js_setprop(js, arr, key, args[i]); 16102 + len++; 16103 + } 16104 + jsval_t len_key = js_mkstr(js, "length", 6); 16105 + jsval_t len_val = tov((double) len); 16106 + js_setprop(js, arr, len_key, len_val); 16107 + return len_val; 16108 + } 16109 + 15882 16110 jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 15883 16111 jsoff_t len = 0; 16112 + 15884 16113 if (off != 0) { 15885 16114 jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 15886 16115 if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); ··· 15889 16118 for (int i = 0; i < nargs; i++) { 15890 16119 char idxstr[16]; 15891 16120 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); 15892 - jsval_t key = js_mkstr(js, idxstr, idxlen); 15893 - js_setprop(js, arr, key, args[i]); 15894 - len++; 16121 + js_mkprop_fast(js, arr, idxstr, idxlen, args[i]); len++; 15895 16122 } 15896 - 15897 - jsval_t len_key = js_mkstr(js, "length", 6); 15898 - jsval_t len_val = tov((double) len); 15899 - 15900 - js_setprop(js, arr, len_key, len_val); 15901 - return len_val; 16123 + 16124 + jsval_t new_len = tov((double) len); 16125 + if (off != 0) saveval(js, off + sizeof(jsoff_t) * 2, new_len); 16126 + else js_mkprop_fast(js, arr, "length", 6, new_len); 16127 + 16128 + return new_len; 15902 16129 } 15903 16130 15904 16131 void js_arr_push(struct js *js, jsval_t arr, jsval_t val) { ··· 15921 16148 } 15922 16149 15923 16150 static jsval_t builtin_array_pop(struct js *js, jsval_t *args, int nargs) { 15924 - (void) args; 15925 - (void) nargs; 15926 16151 jsval_t arr = js->this_val; 15927 16152 15928 16153 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { ··· 15938 16163 } 15939 16164 15940 16165 if (len == 0) return js_mkundef(); 15941 - len--; 15942 - char idxstr[16]; 16166 + len--; char idxstr[16]; 15943 16167 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); 16168 + 16169 + jsoff_t arr_off = (jsoff_t)vdata(arr); 16170 + jsoff_t tail = loadoff(js, arr_off + sizeof(jsoff_t) * 2); 16171 + jsoff_t elem_off = 0; 15944 16172 15945 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 16173 + if (tail != 0 && tail < js->brk) { 16174 + jsoff_t tail_hdr = loadoff(js, tail); 16175 + if ((tail_hdr & SLOTMASK) == 0) { 16176 + jsoff_t tail_koff = loadoff(js, tail + sizeof(jsoff_t)); 16177 + jsoff_t tail_klen = offtolen(loadoff(js, tail_koff)); 16178 + const char *tail_key = (char *)&js->mem[tail_koff + sizeof(jsoff_t)]; 16179 + if (tail_klen == idxlen && memcmp(tail_key, idxstr, idxlen) == 0) elem_off = tail; 16180 + } 16181 + } 16182 + 16183 + if (elem_off == 0) elem_off = lkp(js, arr, idxstr, idxlen); 15946 16184 jsval_t result = js_mkundef(); 15947 - if (elem_off != 0) { 15948 - result = resolveprop(js, mkval(T_PROP, elem_off)); 16185 + if (elem_off != 0) result = resolveprop(js, mkval(T_PROP, elem_off)); 16186 + 16187 + if (is_proxy(js, arr)) { 16188 + jsval_t len_key = js_mkstr(js, "length", 6); 16189 + js_setprop(js, arr, len_key, tov((double) len)); 16190 + } else if (off != 0) { 16191 + saveval(js, off + sizeof(jsoff_t) * 2, tov((double) len)); 16192 + } else { 16193 + jsval_t len_key = js_mkstr(js, "length", 6); 16194 + js_setprop(js, arr, len_key, tov((double) len)); 15949 16195 } 15950 16196 15951 - jsval_t len_key = js_mkstr(js, "length", 6); 15952 - jsval_t len_val = tov((double) len); 15953 - js_setprop(js, arr, len_key, len_val); 15954 16197 js->needs_gc = true; 15955 - 15956 16198 return result; 15957 16199 } 15958 16200 ··· 16142 16384 const char *key; size_t key_len; jsval_t val; 16143 16385 16144 16386 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16145 - unsigned parsed_idx; 16387 + unsigned long parsed_idx; 16146 16388 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16147 16389 16148 16390 if (vtype(val) == vtype(search)) { ··· 16190 16432 jsval_t val; 16191 16433 16192 16434 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16193 - unsigned parsed_idx; 16435 + unsigned long parsed_idx; 16194 16436 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16195 16437 16196 16438 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; ··· 16233 16475 jsval_t val; 16234 16476 16235 16477 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16236 - unsigned parsed_idx; 16478 + unsigned long parsed_idx; 16237 16479 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16238 16480 16239 16481 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; ··· 16275 16517 jsval_t val; 16276 16518 16277 16519 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16278 - unsigned parsed_idx; 16520 + unsigned long parsed_idx; 16279 16521 if (!parse_array_index(key, key_len, len, &parsed_idx) || count >= len) continue; 16280 16522 16281 16523 vals[count] = val; ··· 16329 16571 jsval_t val; 16330 16572 16331 16573 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16332 - unsigned parsed_idx; 16574 + unsigned long parsed_idx; 16333 16575 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16334 16576 16335 16577 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; ··· 16381 16623 jsval_t val; 16382 16624 16383 16625 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16384 - unsigned parsed_idx; 16626 + unsigned long parsed_idx; 16385 16627 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16386 16628 16387 16629 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; ··· 16436 16678 jsval_t val; 16437 16679 16438 16680 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16439 - unsigned parsed_idx; 16681 + unsigned long parsed_idx; 16440 16682 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16441 16683 16442 16684 if (first) { ··· 16475 16717 jsval_t val; 16476 16718 16477 16719 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16478 - unsigned parsed_idx; 16720 + unsigned long parsed_idx; 16479 16721 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16480 16722 16481 16723 if (depth > 0 && (vtype(val) == T_ARR || vtype(val) == T_OBJ)) { ··· 16667 16909 jsval_t val; 16668 16910 16669 16911 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16670 - unsigned parsed_idx; 16912 + unsigned long parsed_idx; 16671 16913 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 16672 16914 16673 16915 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr }; ··· 16713 16955 if (len == 0) return return_index ? tov(-1) : js_mkundef(); 16714 16956 16715 16957 jsval_t *vals = malloc(len * sizeof(jsval_t)); 16716 - unsigned *idxs = malloc(len * sizeof(unsigned)); 16958 + unsigned long *idxs = malloc(len * sizeof(unsigned)); 16717 16959 if (!vals || !idxs) { free(vals); free(idxs); return js_mkerr(js, "out of memory"); } 16718 16960 16719 16961 jsoff_t count = 0; ··· 16721 16963 const char *key; size_t key_len; jsval_t val; 16722 16964 16723 16965 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16724 - unsigned parsed_idx; 16966 + unsigned long parsed_idx; 16725 16967 if (!parse_array_index(key, key_len, len, &parsed_idx) || count >= len) continue; 16726 16968 16727 16969 vals[count] = val; ··· 16740 16982 } 16741 16983 if (js_truthy(js, result)) { 16742 16984 jsval_t found_val = vals[i-1]; 16743 - unsigned found_idx = idxs[i-1]; 16985 + unsigned long found_idx = idxs[i-1]; 16744 16986 free(vals); free(idxs); 16745 16987 return return_index ? tov((double)found_idx) : found_val; 16746 16988 } ··· 17081 17323 jsval_t val; 17082 17324 17083 17325 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 17084 - unsigned parsed_idx; 17326 + unsigned long parsed_idx; 17085 17327 if (!parse_array_index(key, key_len, len, &parsed_idx)) continue; 17086 17328 17087 17329 jsval_t call_args[3] = { val, tov((double)parsed_idx), arr };
+59
tests/bench_array_create.js
··· 1 + /* 2 + * Array creation micro-bench 3 + */ 4 + 5 + function get_clock() { 6 + if (typeof performance !== 'undefined' && performance.now) return performance.now(); 7 + return Date.now(); 8 + } 9 + 10 + function run_case(name, fn, iters) { 11 + var i; 12 + var t0 = get_clock(); 13 + for (i = 0; i < iters; i++) fn(); 14 + var dt = get_clock() - t0; 15 + console.log(name + ': ' + dt.toFixed(2) + ' ms'); 16 + } 17 + 18 + function create_assign() { 19 + var tab = []; 20 + for (var i = 0; i < 1000; i++) tab[i] = i; 21 + } 22 + 23 + function create_push() { 24 + var tab = []; 25 + for (var i = 0; i < 1000; i++) tab.push(i); 26 + } 27 + 28 + function create_prealloc_assign() { 29 + var tab = []; 30 + tab.length = 1000; 31 + for (var i = 0; i < 1000; i++) tab[i] = i; 32 + } 33 + 34 + function create_prealloc_push() { 35 + var tab = []; 36 + tab.length = 1000; 37 + for (var i = 0; i < 1000; i++) tab[i] = i; 38 + } 39 + 40 + function main() { 41 + var iters = 200; 42 + run_case('create_assign', create_assign, iters); 43 + run_case('create_push', create_push, iters); 44 + run_case('create_prealloc_assign', create_prealloc_assign, iters); 45 + run_case('create_prealloc_push', create_prealloc_push, iters); 46 + 47 + var arr = []; 48 + var t0 = get_clock(); 49 + for (var i = 0; i < 20000; i++) { 50 + arr.push(i); 51 + } 52 + var dt = get_clock() - t0; 53 + console.log('push_20k: ' + dt.toFixed(2) + ' ms'); 54 + console.log('done, arr length: ' + arr.length); 55 + console.log('first element: ' + arr[0]); 56 + console.log('last element: ' + arr[19999]); 57 + } 58 + 59 + main();