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.

add support for small objects and inline mode in stringification

+155 -87
+1 -1
examples/rou3/bench.js
··· 1 - import { createRouter, addRoute, findRoute } from './'; 1 + import { createRouter, addRoute, findRoute } from './index.js'; 2 2 3 3 const router = createRouter(); 4 4
+2
include/ant.h
··· 12 12 13 13 #define STR_PROTO "__proto__" 14 14 #define STR_PROTO_LEN 9 15 + 15 16 #define ANT_LIMIT_SIZE_CACHE 16384 17 + #define ANT_STRING(s) js_mkstr(js, s, sizeof(s) - 1) 16 18 17 19 struct js; 18 20
+1 -1
meson.build
··· 96 96 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 97 97 98 98 version_conf = configuration_data() 99 - version_conf.set('ANT_VERSION', '0.3.2.30') 99 + version_conf.set('ANT_VERSION', '0.3.2.31') 100 100 version_conf.set('ANT_GIT_HASH', git_hash) 101 101 version_conf.set('ANT_BUILD_DATE', build_date) 102 102
+140 -78
src/ant.c
··· 1259 1259 if (ref) return ref > 0 ? (size_t) snprintf(buf, len, "[Circular *%d]", ref) : cpy(buf, len, "[Circular]", 10); 1260 1260 1261 1261 push_stringify(obj); 1262 - size_t n = cpy(buf, len, "[ ", 2); 1263 1262 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1264 1263 jsoff_t length = 0; 1265 1264 jsoff_t scan = next; ··· 1276 1275 } 1277 1276 scan = loadoff(js, scan) & ~(3U | FLAGMASK); 1278 1277 } 1278 + 1279 + size_t n = cpy(buf, len, length > 0 ? "[ " : "[", length > 0 ? 2 : 1); 1279 1280 1280 1281 for (jsoff_t i = 0; i < length; i++) { 1281 1282 if (i > 0) n += cpy(buf + n, len - n, ", ", 2); ··· 1307 1308 } 1308 1309 } 1309 1310 1310 - n += cpy(buf + n, len - n, " ]", 2); 1311 + n += cpy(buf + n, len - n, length > 0 ? " ]" : "]", length > 0 ? 2 : 1); 1311 1312 pop_stringify(); 1312 1313 return n; 1313 1314 } ··· 1512 1513 return n; 1513 1514 } 1514 1515 1516 + static bool is_small_object(struct js *js, jsval_t obj, int *prop_count) { 1517 + int count = 0; 1518 + bool has_nested = false; 1519 + jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1520 + 1521 + while (next < js->brk && next != 0) { 1522 + jsoff_t header = loadoff(js, next); 1523 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 1524 + 1525 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1526 + jsoff_t klen = offtolen(loadoff(js, koff)); 1527 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 1528 + 1529 + bool is_desc = (klen > 7 && key[0] == '_' && key[1] == '_' && key[2] == 'd' && key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_'); 1530 + const char *tag_sym_key = get_toStringTag_sym_key(); 1531 + bool should_hide = streq(key, klen, STR_PROTO, STR_PROTO_LEN) || streq(key, klen, tag_sym_key, strlen(tag_sym_key)) || is_desc; 1532 + 1533 + if (!should_hide) { 1534 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1535 + uint8_t t = vtype(val); 1536 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) has_nested = true; 1537 + count++; 1538 + } 1539 + next = next_prop(header); 1540 + } 1541 + 1542 + if (prop_count) *prop_count = count; 1543 + return count <= 4 && !has_nested; 1544 + } 1545 + 1515 1546 static size_t strobj(struct js *js, jsval_t obj, char *buf, size_t len) { 1516 1547 jsoff_t time_off = lkp(js, obj, "__time", 6); 1517 1548 if (time_off != 0) return strdate(js, obj, buf, len); ··· 1532 1563 bool is_map = false, is_set = false; 1533 1564 jsoff_t tlen = 0, toff = 0; 1534 1565 const char *tag_str = NULL; 1566 + int prop_count = 0; 1567 + bool inline_mode = false; 1535 1568 1536 1569 if (tag_off == 0) goto print_plain_object; 1537 1570 ··· 1628 1661 goto continue_object_print; 1629 1662 1630 1663 print_plain_object: 1631 - n += cpy(buf + n, len - n, "{\n", 2); 1664 + inline_mode = is_small_object(js, obj, &prop_count); 1665 + 1666 + jsval_t proto_val = js_get_proto(js, obj); 1667 + bool is_null_proto = (vtype(proto_val) == T_NULL); 1668 + const char *class_name = NULL; 1669 + jsoff_t class_name_len = 0; 1670 + 1671 + do { 1672 + if (is_null_proto) break; 1673 + uint8_t pt = vtype(proto_val); 1674 + if (pt != T_OBJ && pt != T_FUNC) break; 1675 + 1676 + jsoff_t ctor_off = lkp(js, proto_val, "constructor", 11); 1677 + if (ctor_off == 0) break; 1678 + 1679 + jsval_t ctor_val = resolveprop(js, mkval(T_PROP, ctor_off)); 1680 + if (vtype(ctor_val) != T_FUNC) break; 1681 + 1682 + jsoff_t name_off = lkp(js, mkval(T_OBJ, vdata(ctor_val)), "name", 4); 1683 + if (name_off == 0) break; 1684 + 1685 + jsval_t name_val = resolveprop(js, mkval(T_PROP, name_off)); 1686 + if (vtype(name_val) != T_STR) break; 1687 + 1688 + jsoff_t name_str_off = vstr(js, name_val, &class_name_len); 1689 + class_name = (const char *) &js->mem[name_str_off]; 1690 + 1691 + if (class_name_len == 6 && memcmp(class_name, "Object", 6) == 0) { 1692 + class_name = NULL; 1693 + class_name_len = 0; 1694 + } 1695 + } while (0); 1632 1696 1633 - continue_object_print: 1697 + if (prop_count == 0) { 1698 + if (is_null_proto) { 1699 + n += cpy(buf + n, len - n, "[Object: null prototype] {}", 27); 1700 + } else if (class_name && class_name_len > 0) { 1701 + n += cpy(buf + n, len - n, class_name, class_name_len); 1702 + n += cpy(buf + n, len - n, " {}", 3); 1703 + } else { 1704 + n += cpy(buf + n, len - n, "{}", 2); 1705 + } 1706 + pop_stringify(); 1707 + return n; 1708 + } 1634 1709 1635 - stringify_indent++; 1710 + if (is_null_proto) { 1711 + n += cpy(buf + n, len - n, "[Object: null prototype] ", 25); 1712 + } else if (class_name && class_name_len > 0) { 1713 + n += cpy(buf + n, len - n, class_name, class_name_len); 1714 + n += cpy(buf + n, len - n, " ", 1); 1715 + } 1716 + 1717 + n += cpy(buf + n, len - n, inline_mode ? "{ " : "{\n", 2); 1718 + 1719 + continue_object_print:; 1720 + 1721 + if (!inline_mode) stringify_indent++; 1636 1722 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1637 1723 bool first = true; 1724 + 1725 + int prop_capacity = 64; 1726 + jsoff_t *prop_offsets = malloc(prop_capacity * sizeof(jsoff_t)); 1727 + int num_props = 0; 1638 1728 1639 1729 while (next < js->brk && next != 0) { 1640 1730 jsoff_t header = loadoff(js, next); ··· 1661 1751 } 1662 1752 1663 1753 if (!should_hide) { 1664 - jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1665 - if (!first) n += cpy(buf + n, len - n, ",\n", 2); 1666 - first = false; 1667 - n += add_indent(buf + n, len - n, stringify_indent); 1668 - 1669 - bool is_special_global = false; 1670 - if (vtype(val) == T_UNDEF && streq(key, klen, "undefined", 9)) { 1671 - is_special_global = true; 1672 - } else if (vtype(val) == T_NUM) { 1673 - double d = tod(val); 1674 - if (isinf(d) && d > 0 && streq(key, klen, "Infinity", 8)) { 1675 - is_special_global = true; 1676 - } else if (isnan(d) && streq(key, klen, "NaN", 3)) { 1677 - is_special_global = true; 1678 - } 1754 + if (num_props >= prop_capacity) { 1755 + prop_capacity *= 2; 1756 + prop_offsets = realloc(prop_offsets, prop_capacity * sizeof(jsoff_t)); 1679 1757 } 1680 - 1681 - if (is_special_global) { 1682 - n += tostr(js, val, buf + n, len - n); 1683 - } else { 1684 - n += strkey(js, mkval(T_STR, koff), buf + n, len - n); 1685 - n += cpy(buf + n, len - n, ": ", 2); 1686 - n += tostr(js, val, buf + n, len - n); 1687 - } 1758 + prop_offsets[num_props++] = next; 1688 1759 } 1689 1760 next = next_prop(header); 1690 1761 } 1762 + 1763 + for (int i = num_props - 1; i >= 0; i--) { 1764 + jsoff_t prop = prop_offsets[i]; 1765 + jsoff_t koff = loadoff(js, prop + (jsoff_t) sizeof(prop)); 1766 + jsoff_t klen = offtolen(loadoff(js, koff)); 1767 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 1768 + jsval_t val = loadval(js, prop + (jsoff_t) (sizeof(prop) + sizeof(koff))); 1769 + 1770 + if (!first) n += cpy(buf + n, len - n, inline_mode ? ", " : ",\n", 2); 1771 + first = false; 1772 + if (!inline_mode) n += add_indent(buf + n, len - n, stringify_indent); 1773 + 1774 + bool is_special_global = false; 1775 + if (vtype(val) == T_UNDEF && streq(key, klen, "undefined", 9)) { 1776 + is_special_global = true; 1777 + } else if (vtype(val) == T_NUM) { 1778 + double d = tod(val); 1779 + if (isinf(d) && d > 0 && streq(key, klen, "Infinity", 8)) { 1780 + is_special_global = true; 1781 + } else if (isnan(d) && streq(key, klen, "NaN", 3)) is_special_global = true; 1782 + } 1783 + 1784 + if (is_special_global) { 1785 + n += tostr(js, val, buf + n, len - n); 1786 + } else { 1787 + n += strkey(js, mkval(T_STR, koff), buf + n, len - n); 1788 + n += cpy(buf + n, len - n, ": ", 2); 1789 + n += tostr(js, val, buf + n, len - n); 1790 + } 1791 + } 1792 + free(prop_offsets); 1691 1793 1692 1794 next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | FLAGMASK); 1693 1795 while (next < js->brk && next != 0) { ··· 1748 1850 next = next_prop(header); 1749 1851 } 1750 1852 1751 - stringify_indent--; 1752 - if (!first) n += cpy(buf + n, len - n, "\n", 1); 1753 - n += add_indent(buf + n, len - n, stringify_indent); 1754 - n += cpy(buf + n, len - n, "}", 1); 1853 + if (!inline_mode) stringify_indent--; 1854 + if (inline_mode) { 1855 + n += cpy(buf + n, len - n, " }", 2); 1856 + } else { 1857 + if (!first) n += cpy(buf + n, len - n, "\n", 1); 1858 + n += add_indent(buf + n, len - n, stringify_indent); 1859 + n += cpy(buf + n, len - n, "}", 1); 1860 + } 1755 1861 pop_stringify(); 1756 1862 return n; 1757 1863 } ··· 1876 1982 return false; 1877 1983 } 1878 1984 1879 - static size_t strfunc_ctor(struct js *js, jsval_t func_obj, char *buf, size_t len) { 1880 - int ref = get_circular_ref(func_obj); 1881 - if (ref) return ref > 0 ? (size_t) snprintf(buf, len, "[Circular *%d]", ref) : cpy(buf, len, "[Circular]", 10); 1882 - push_stringify(func_obj); 1883 - 1884 - size_t n = cpy(buf, len, "{\n", 2); 1885 - stringify_indent++; 1886 - bool first = true; 1887 - 1888 - jsoff_t next = loadoff(js, (jsoff_t) vdata(func_obj)) & ~(3U | FLAGMASK); 1889 - while (next < js->brk && next != 0) { 1890 - jsoff_t header = loadoff(js, next); 1891 - if (is_slot_prop(header)) { next = next_prop(header); continue; } 1892 - 1893 - jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1894 - jsoff_t klen = offtolen(loadoff(js, koff)); 1895 - const char *kstr = (const char *) &js->mem[koff + sizeof(jsoff_t)]; 1896 - 1897 - if (!is_hidden_func_prop(kstr, koff, klen)) { 1898 - jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1899 - if (!first) n += cpy(buf + n, len - n, ",\n", 2); 1900 - first = false; 1901 - n += add_indent(buf + n, len - n, stringify_indent); 1902 - n += strkey(js, mkval(T_STR, koff), buf + n, len - n); 1903 - n += cpy(buf + n, len - n, ": ", 2); 1904 - n += tostr(js, val, buf + n, len - n); 1905 - } 1906 - next = next_prop(header); 1907 - } 1908 - 1909 - jsoff_t proto_off = lkp_interned(js, func_obj, INTERN_PROTOTYPE, 9); 1910 - if (proto_off != 0) { 1911 - jsval_t proto_val = resolveprop(js, mkval(T_PROP, proto_off)); 1912 - if (vtype(proto_val) == T_OBJ && !is_on_stack(proto_val)) n += print_prototype(js, proto_val, buf + n, len - n, &first); 1913 - } 1914 - 1915 - stringify_indent--; 1916 - if (!first) n += cpy(buf + n, len - n, "\n", 1); 1917 - n += add_indent(buf + n, len - n, stringify_indent); 1918 - n += cpy(buf + n, len - n, "}", 1); 1919 - pop_stringify(); 1920 - return n; 1921 - } 1922 - 1923 1985 static size_t strfunc(struct js *js, jsval_t value, char *buf, size_t len) { 1924 1986 jsval_t func_obj = mkval(T_OBJ, vdata(value)); 1925 1987 jsval_t code_slot = get_slot(js, func_obj, SLOT_CODE); ··· 1938 2000 1939 2001 if (vtype(code_slot) != T_STR) { 1940 2002 jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 1941 - if (vtype(cfunc_slot) == T_CFUNC) return strfunc_ctor(js, func_obj, buf, len); 2003 + if (vtype(cfunc_slot) == T_CFUNC) return cpy(buf, len, "[Function (native)]", 19); 1942 2004 if (name && name_len > 0) { 1943 2005 size_t n = cpy(buf, len, "[Function: ", 11); 1944 2006 n += cpy(buf + n, len - n, name, name_len); ··· 1961 2023 1962 2024 jsoff_t sn, off = vstr(js, code_val, &sn); 1963 2025 if (sn >= 9 && memcmp(&js->mem[off], "__builtin", 9) == 0) { 1964 - return strfunc_ctor(js, func_obj, buf, len); 2026 + return cpy(buf, len, "[Function (native)]", 19); 1965 2027 } 1966 2028 1967 2029 if (name && name_len > 0) {
+2 -2
src/modules/io.c
··· 211 211 continue; 212 212 } 213 213 214 - if (strncmp(p, "Infinity", 8) == 0 && !is_key) { 214 + if (strncmp(p, "Infinity", 8) == 0 && !isalnum((unsigned char)p[8]) && p[8] != '_') { 215 215 io_puts(JSON_NUMBER, stream); 216 216 io_puts("Infinity", stream); 217 217 io_puts(ANSI_RESET, stream); ··· 219 219 continue; 220 220 } 221 221 222 - if (strncmp(p, "NaN", 3) == 0 && !isalnum((unsigned char)p[3]) && p[3] != '_' && !is_key) { 222 + if (strncmp(p, "NaN", 3) == 0 && !isalnum((unsigned char)p[3]) && p[3] != '_') { 223 223 io_puts(JSON_NUMBER, stream); 224 224 io_puts("NaN", stream); 225 225 io_puts(ANSI_RESET, stream);
+7 -3
src/modules/performance.c
··· 3 3 #include <sys/time.h> 4 4 #include <time.h> 5 5 6 + #include "ant.h" 6 7 #include "runtime.h" 8 + #include "modules/symbol.h" 7 9 #include "modules/performance.h" 8 10 9 11 static double time_origin_ms = 0; ··· 29 31 30 32 void init_performance_module() { 31 33 struct js *js = rt->js; 32 - jsval_t global = js_glob(js); 33 34 35 + jsval_t glob = js_glob(js); 36 + jsval_t perf_obj = js_mkobj(js); 37 + 34 38 time_origin_ms = get_current_time_ms(); 35 39 36 - jsval_t perf_obj = js_mkobj(js); 37 40 js_set(js, perf_obj, "now", js_mkfun(js_performance_now)); 38 41 js_set(js, perf_obj, "timeOrigin", js_mknum(time_origin_ms)); 39 42 40 - js_set(js, global, "performance", perf_obj); 43 + js_set(js, perf_obj, get_toStringTag_sym_key(), ANT_STRING("Performance")); 44 + js_set(js, glob, "performance", perf_obj); 41 45 }
+2 -2
src/modules/sessionstorage.c
··· 172 172 173 173 void init_sessionstorage_module(void) { 174 174 struct js *js = rt->js; 175 - jsval_t glob = js_glob(js); 176 175 176 + jsval_t glob = js_glob(js); 177 177 jsval_t storage_obj = js_mkobj(js); 178 178 179 179 js_set(js, storage_obj, "setItem", js_mkfun(js_sessionstorage_setItem)); ··· 185 185 jsval_t length_getter = js_mkfun(js_sessionstorage_length); 186 186 js_set_getter_desc(js, storage_obj, "length", 6, length_getter, JS_DESC_E); 187 187 188 - js_set(js, storage_obj, get_toStringTag_sym_key(), js_mkstr(js, "Storage", 7)); 188 + js_set(js, storage_obj, get_toStringTag_sym_key(), ANT_STRING("Storage")); 189 189 js_set(js, glob, "sessionStorage", storage_obj); 190 190 }