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 interned property lookup

+134 -20
+125 -20
src/ant.c
··· 2072 2072 2073 2073 static bool is_hidden_func_prop(const char *key, jsoff_t koff, jsoff_t klen) { 2074 2074 if (klen == 4 && memcmp(key, "name", 4) == 0) return true; 2075 - 2076 2075 if (key[0] == '_' && key[1] == '_') return true; 2077 2076 2078 2077 const char *interned = intern_string(key, klen); ··· 4486 4485 static jsval_t js_func_decl(struct js *js); 4487 4486 static jsval_t js_func_decl_async(struct js *js); 4488 4487 4488 + static inline bool is_function_keyword(const char *code, jsoff_t pos, jsoff_t end) { 4489 + if (pos + 8 > end) return false; 4490 + uint64_t word; 4491 + memcpy(&word, code + pos, 8); 4492 + 4493 + if (word != 0x6e6f6974636e7566ULL) return false; 4494 + return (pos + 8 >= end) || !IS_IDENT(code[pos + 8]); 4495 + } 4496 + 4497 + static inline bool is_async_function(const char *code, jsoff_t pos, jsoff_t end) { 4498 + if (pos + 5 > end) return false; 4499 + 4500 + uint32_t word4; 4501 + memcpy(&word4, code + pos, 4); 4502 + 4503 + if (word4 != 0x6e797361U || code[pos + 4] != 'c') return false; 4504 + if (pos + 5 < end && IS_IDENT(code[pos + 5])) return false; 4505 + 4506 + jsoff_t scan = pos + 5; 4507 + while (scan < end && ( 4508 + code[scan] == ' ' || 4509 + code[scan] == '\t' || 4510 + code[scan] == '\n' || 4511 + code[scan] == '\r' 4512 + )) scan++; 4513 + 4514 + return is_function_keyword(code, scan, end); 4515 + } 4516 + 4517 + static bool block_has_function_decl(struct js *js) { 4518 + const char *code = js->code; 4519 + jsoff_t pos = js->pos; 4520 + jsoff_t end = js->clen; 4521 + int depth = 0; 4522 + 4523 + while (pos < end) { 4524 + uint8_t c = (uint8_t)code[pos]; 4525 + 4526 + if (c == '"' || c == '\'' || c == '`') { 4527 + uint8_t quote = c; 4528 + pos++; 4529 + while (pos < end && (uint8_t)code[pos] != quote) { 4530 + if (code[pos] == '\\' && pos + 1 < end) pos++; 4531 + pos++; 4532 + } 4533 + if (pos < end) pos++; 4534 + continue; 4535 + } 4536 + 4537 + if (c == '/' && pos + 1 < end) { 4538 + if (code[pos + 1] == '/') { 4539 + pos += 2; 4540 + while (pos < end && code[pos] != '\n') pos++; 4541 + continue; 4542 + } 4543 + if (code[pos + 1] == '*') { 4544 + pos += 2; 4545 + while (pos + 1 < end && !(code[pos] == '*' && code[pos + 1] == '/')) pos++; 4546 + if (pos + 1 < end) pos += 2; 4547 + continue; 4548 + } 4549 + } 4550 + 4551 + if (c == '{') { depth++; pos++; continue; } 4552 + if (c == '}') { 4553 + if (depth == 0) break; 4554 + depth--; pos++; continue; 4555 + } 4556 + 4557 + if (depth == 0) { 4558 + if (c == 'f' && is_function_keyword(code, pos, end)) return true; 4559 + if (c == 'a' && is_async_function(code, pos, end)) return true; 4560 + } 4561 + 4562 + pos++; 4563 + } 4564 + 4565 + return false; 4566 + } 4567 + 4568 + static inline bool might_have_function_decl(const char *code, size_t len) { 4569 + return memmem(code, len, "function", 8) != NULL; 4570 + } 4571 + 4489 4572 static void hoist_function_declarations(struct js *js) { 4490 4573 if (js->flags & F_NOEXEC) return; 4491 4574 if (js->is_hoisting) return; 4575 + 4576 + if (!memmem(js->code + js->pos, js->clen - js->pos, "function", 8)) return; 4577 + if (!block_has_function_decl(js)) return; 4492 4578 4493 4579 js->is_hoisting = true; 4494 4580 ··· 4582 4668 4583 4669 static inline jsoff_t lkp_interned(struct js *js, jsval_t obj, const char *search_intern, size_t len) { 4584 4670 jsoff_t obj_off = (jsoff_t)vdata(obj); 4585 - 4586 - jsval_t version_val = get_slot(js, mkval(T_OBJ, obj_off), SLOT_VERSION); 4587 - uint32_t current_version = (vtype(version_val) == T_NUM) ? (uint32_t)tod(version_val) : 0; 4671 + jsoff_t first_prop = loadoff(js, obj_off) & ~(3U | FLAGMASK); 4588 4672 4589 4673 uint32_t cache_slot = (((uintptr_t)search_intern >> 3) ^ obj_off) & (ANT_LIMIT_SIZE_CACHE - 1); 4590 4674 intern_prop_cache_entry_t *ce = &intern_prop_cache[cache_slot]; 4591 - if (ce->obj_off == obj_off && ce->intern_ptr == search_intern && ce->obj_version == current_version) { 4675 + 4676 + if (ce->obj_off == obj_off && ce->intern_ptr == search_intern && ce->obj_version == first_prop) { 4592 4677 return ce->prop_off; 4593 4678 } 4594 4679 4595 - jsoff_t off = loadoff(js, obj_off) & ~(3U | FLAGMASK); 4680 + jsoff_t off = first_prop; 4596 4681 while (off < js->brk && off != 0) { 4597 4682 jsoff_t header = loadoff(js, off); 4598 4683 if (is_slot_prop(header)) { off = next_prop(header); continue; } ··· 4605 4690 ce->obj_off = obj_off; 4606 4691 ce->intern_ptr = search_intern; 4607 4692 ce->prop_off = off; 4608 - ce->obj_version = current_version; 4693 + ce->obj_version = first_prop; 4609 4694 return off; 4610 4695 } 4611 4696 } ··· 4615 4700 ce->obj_off = obj_off; 4616 4701 ce->intern_ptr = search_intern; 4617 4702 ce->prop_off = 0; 4618 - ce->obj_version = current_version; 4703 + ce->obj_version = first_prop; 4619 4704 4620 4705 return 0; 4621 4706 } ··· 6805 6890 } 6806 6891 6807 6892 L_TOK_PLUS: { 6893 + if (vtype(l) == T_NUM && vtype(r) == T_NUM) return tov(tod(l) + tod(r)); 6808 6894 jsval_t lu = unwrap_primitive(js, l); 6809 6895 jsval_t ru = unwrap_primitive(js, r); 6810 6896 if (vtype(lu) == T_BIGINT && vtype(ru) == T_BIGINT) return bigint_add(js, lu, ru); ··· 6824 6910 L_TOK_DIV: 6825 6911 L_TOK_REM: 6826 6912 L_TOK_EXP: { 6827 - if (vtype(l) == T_BIGINT && vtype(r) == T_BIGINT) { 6913 + uint8_t lt = vtype(l), rt = vtype(r); 6914 + if (lt == T_NUM && rt == T_NUM) { 6915 + double a = tod(l), b = tod(r); 6916 + switch (op) { 6917 + case TOK_MINUS: return tov(a - b); 6918 + case TOK_MUL: return tov(a * b); 6919 + case TOK_DIV: return tov(a / b); 6920 + case TOK_REM: return tov(a - b * ((double)(long)(a / b))); 6921 + case TOK_EXP: return tov(pow(a, b)); 6922 + } 6923 + } 6924 + if (lt == T_BIGINT && rt == T_BIGINT) { 6828 6925 switch (op) { 6829 6926 case TOK_MINUS: return bigint_sub(js, l, r); 6830 6927 case TOK_MUL: return bigint_mul(js, l, r); ··· 6833 6930 case TOK_EXP: return bigint_exp(js, l, r); 6834 6931 } 6835 6932 } 6836 - if (vtype(l) == T_BIGINT || vtype(r) == T_BIGINT) 6933 + if (lt == T_BIGINT || rt == T_BIGINT) 6837 6934 return js_mkerr(js, "Cannot mix BigInt value and other types"); 6838 6935 double a = js_to_number(js, l), b = js_to_number(js, r); 6839 6936 switch (op) { ··· 6849 6946 L_TOK_LE: 6850 6947 L_TOK_GT: 6851 6948 L_TOK_GE: { 6852 - if (vtype(l) == T_BIGINT && vtype(r) == T_BIGINT) { 6949 + uint8_t lt = vtype(l), rt = vtype(r); 6950 + if (lt == T_NUM && rt == T_NUM) { 6951 + double a = tod(l), b = tod(r); 6952 + switch (op) { 6953 + case TOK_LT: return mkval(T_BOOL, a < b); 6954 + case TOK_LE: return mkval(T_BOOL, a <= b); 6955 + case TOK_GT: return mkval(T_BOOL, a > b); 6956 + case TOK_GE: return mkval(T_BOOL, a >= b); 6957 + } 6958 + } 6959 + if (lt == T_BIGINT && rt == T_BIGINT) { 6853 6960 int cmp = bigint_compare(js, l, r); 6854 6961 switch (op) { 6855 6962 case TOK_LT: return mkval(T_BOOL, cmp < 0); ··· 6858 6965 case TOK_GE: return mkval(T_BOOL, cmp >= 0); 6859 6966 } 6860 6967 } 6861 - if (vtype(l) == T_BIGINT || vtype(r) == T_BIGINT) 6968 + if (lt == T_BIGINT || rt == T_BIGINT) 6862 6969 return js_mkerr(js, "Cannot mix BigInt value and other types"); 6863 - if (vtype(l) == T_STR && vtype(r) == T_STR) 6970 + if (lt == T_STR && rt == T_STR) 6864 6971 return do_string_op(js, op, l, r); 6865 6972 double a = js_to_number(js, l), b = js_to_number(js, r); 6866 6973 switch (op) { ··· 6877 6984 L_TOK_SHL: 6878 6985 L_TOK_SHR: 6879 6986 L_TOK_ZSHR: { 6880 - if (vtype(l) == T_BIGINT || vtype(r) == T_BIGINT) 6987 + uint8_t lt = vtype(l), rt = vtype(r); 6988 + if (lt == T_BIGINT || rt == T_BIGINT) 6881 6989 return js_mkerr(js, "Cannot mix BigInt value and other types"); 6882 - int32_t ai = js_to_int32(js_to_number(js, l)); 6883 - uint32_t bi = js_to_uint32(js_to_number(js, r)); 6990 + int32_t ai = (lt == T_NUM) ? js_to_int32(tod(l)) : js_to_int32(js_to_number(js, l)); 6991 + uint32_t bi = (rt == T_NUM) ? js_to_uint32(tod(r)) : js_to_uint32(js_to_number(js, r)); 6884 6992 switch (op) { 6885 6993 case TOK_XOR: return tov((double)(ai ^ (int32_t)bi)); 6886 6994 case TOK_AND: return tov((double)(ai & (int32_t)bi)); ··· 7923 8031 7924 8032 if (!(flags & F_NOEXEC)) { 7925 8033 set_slot(js, func_obj, SLOT_SCOPE, js->scope); 7926 - 7927 - if (flags & F_STRICT) { 7928 - set_slot(js, func_obj, SLOT_STRICT, js_mktrue()); 7929 - } 8034 + if (flags & F_STRICT) set_slot(js, func_obj, SLOT_STRICT, js_mktrue()); 7930 8035 } 7931 8036 7932 8037 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj));
+9
tests/bench_loop_string.js
··· 1 + const obj = { a: 42 }; 2 + const iterations = 200000; 3 + 4 + let start = Date.now(); 5 + let result = 0; 6 + for (let i = 0; i < iterations; i++) { 7 + result += obj.a; 8 + } 9 + console.log(`loop string access: ${Date.now() - start}ms (result: ${result})`);