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.

introduce rope data structure for strings

+262 -53
+13
include/gc.h
··· 4 4 #include <types.h> 5 5 #include <stddef.h> 6 6 7 + #define ROPE_FLAG (1ULL << 63) 8 + #define ROPE_DEPTH_SHIFT 56 9 + #define ROPE_DEPTH_MASK 0x7FULL 10 + #define ROPE_MAX_DEPTH 64 11 + #define ROPE_FLATTEN_THRESHOLD (32 * 1024) 12 + 13 + typedef struct { 14 + jsoff_t header; 15 + jsval_t left; 16 + jsval_t right; 17 + jsval_t cached; 18 + } rope_node_t; 19 + 7 20 #define GC_FWD_LOAD_FACTOR 70 8 21 #define GC_ROOTS_INITIAL_CAP 32 9 22
+227 -52
src/ant.c
··· 5 5 #include <compat.h> // IWYU pragma: keep 6 6 7 7 #include "ant.h" 8 + #include "gc.h" 8 9 #include "tokens.h" 9 10 #include "common.h" 10 11 #include "arena.h" ··· 639 640 return (loadoff(js, off) & ARRMASK) != 0; 640 641 } 641 642 642 - static jsoff_t vstrlen(struct js *js, jsval_t v) { 643 - return offtolen(loadoff(js, (jsoff_t) vdata(v))); 644 - } 645 - 646 643 static inline jsval_t loadval(struct js *js, jsoff_t off) { 647 644 return *(jsval_t *)(&js->mem[off]); 648 645 } 649 646 650 647 static jsval_t upper(struct js *js, jsval_t scope) { 651 648 return mkval(T_OBJ, loadoff(js, (jsoff_t) (vdata(scope) + sizeof(jsoff_t)))); 649 + } 650 + 651 + static jsoff_t vstrlen(struct js *js, jsval_t v) { 652 + jsoff_t off = (jsoff_t) vdata(v); 653 + jsoff_t header = loadoff(js, off); 654 + if (header & ROPE_FLAG) { 655 + return offtolen(header & ~(ROPE_FLAG | (ROPE_DEPTH_MASK << ROPE_DEPTH_SHIFT))); 656 + } 657 + return offtolen(header); 652 658 } 653 659 654 660 #define EXPECT(_tok, ...) \ ··· 1771 1777 int result = snprintf(temp, sizeof(temp), "%.17g", dv); 1772 1778 fix_exponent(temp, (size_t)result); 1773 1779 return cpy(buf, len, temp, strlen(temp)); 1780 + } 1781 + 1782 + static inline bool is_rope(struct js *js, jsval_t value) { 1783 + jsoff_t off = (jsoff_t) vdata(value); 1784 + jsoff_t header = loadoff(js, off); 1785 + return (header & ROPE_FLAG) != 0; 1786 + } 1787 + 1788 + static inline jsoff_t rope_len(struct js *js, jsval_t value) { 1789 + jsoff_t off = (jsoff_t) vdata(value); 1790 + jsoff_t header = loadoff(js, off); 1791 + return offtolen(header & ~(ROPE_FLAG | (ROPE_DEPTH_MASK << ROPE_DEPTH_SHIFT))); 1792 + } 1793 + 1794 + static inline uint8_t rope_depth(struct js *js, jsval_t value) { 1795 + jsoff_t off = (jsoff_t) vdata(value); 1796 + jsoff_t header = loadoff(js, off); 1797 + return (uint8_t)((header >> ROPE_DEPTH_SHIFT) & ROPE_DEPTH_MASK); 1798 + } 1799 + 1800 + static inline jsval_t rope_left(struct js *js, jsval_t value) { 1801 + jsoff_t off = (jsoff_t) vdata(value); 1802 + return loadval(js, off + offsetof(rope_node_t, left)); 1803 + } 1804 + 1805 + static inline jsval_t rope_right(struct js *js, jsval_t value) { 1806 + jsoff_t off = (jsoff_t) vdata(value); 1807 + return loadval(js, off + offsetof(rope_node_t, right)); 1808 + } 1809 + 1810 + static inline jsval_t rope_cached_flat(struct js *js, jsval_t value) { 1811 + jsoff_t off = (jsoff_t) vdata(value); 1812 + return loadval(js, off + offsetof(rope_node_t, cached)); 1813 + } 1814 + 1815 + static inline void rope_set_cached_flat(struct js *js, jsval_t rope, jsval_t flat) { 1816 + jsoff_t off = (jsoff_t) vdata(rope); 1817 + saveval(js, off + offsetof(rope_node_t, cached), flat); 1818 + } 1819 + 1820 + static void rope_flatten_into(struct js *js, jsval_t str, char *dest, jsoff_t *pos) { 1821 + if (vtype(str) != T_STR) return; 1822 + 1823 + if (!is_rope(js, str)) { 1824 + jsoff_t slen; 1825 + jsoff_t soff = (jsoff_t) vdata(str); 1826 + slen = offtolen(loadoff(js, soff)); 1827 + memcpy(dest + *pos, &js->mem[soff + sizeof(jsoff_t)], slen); 1828 + *pos += slen; return; 1829 + } 1830 + 1831 + jsval_t cached = rope_cached_flat(js, str); 1832 + if (vtype(cached) == T_STR && !is_rope(js, cached)) { 1833 + jsoff_t clen; 1834 + jsoff_t coff = (jsoff_t) vdata(cached); 1835 + clen = offtolen(loadoff(js, coff)); 1836 + memcpy(dest + *pos, &js->mem[coff + sizeof(jsoff_t)], clen); 1837 + *pos += clen; return; 1838 + } 1839 + 1840 + jsval_t stack[ROPE_MAX_DEPTH + 8]; 1841 + int sp = 0; stack[sp++] = str; 1842 + 1843 + while (sp > 0) { 1844 + jsval_t node = stack[--sp]; 1845 + if (vtype(node) != T_STR) continue; 1846 + 1847 + if (!is_rope(js, node)) { 1848 + jsoff_t slen; 1849 + jsoff_t soff = (jsoff_t) vdata(node); 1850 + slen = offtolen(loadoff(js, soff)); 1851 + memcpy(dest + *pos, &js->mem[soff + sizeof(jsoff_t)], slen); 1852 + *pos += slen; continue; 1853 + } 1854 + 1855 + jsval_t c = rope_cached_flat(js, node); 1856 + if (vtype(c) == T_STR && !is_rope(js, c)) { 1857 + jsoff_t clen; 1858 + jsoff_t coff = (jsoff_t) vdata(c); 1859 + clen = offtolen(loadoff(js, coff)); 1860 + memcpy(dest + *pos, &js->mem[coff + sizeof(jsoff_t)], clen); 1861 + *pos += clen; continue; 1862 + } 1863 + 1864 + if (sp + 2 <= ROPE_MAX_DEPTH + 8) { 1865 + stack[sp++] = rope_right(js, node); 1866 + stack[sp++] = rope_left(js, node); 1867 + } 1868 + } 1869 + } 1870 + 1871 + static jsval_t rope_flatten(struct js *js, jsval_t rope) { 1872 + if (!is_rope(js, rope)) return rope; 1873 + 1874 + jsval_t cached = rope_cached_flat(js, rope); 1875 + if (vtype(cached) == T_STR && !is_rope(js, cached)) return cached; 1876 + 1877 + jsoff_t total_len = rope_len(js, rope); 1878 + 1879 + char *buf = (char *)ant_calloc(total_len + 1); 1880 + if (!buf) return js_mkerr(js, "oom"); 1881 + 1882 + jsoff_t pos = 0; 1883 + rope_flatten_into(js, rope, buf, &pos); 1884 + buf[pos] = '\0'; 1885 + 1886 + jsval_t flat = js_mkstr(js, buf, pos); 1887 + free(buf); 1888 + 1889 + if (!is_err(flat)) { 1890 + rope_set_cached_flat(js, rope, flat); 1891 + } 1892 + 1893 + return flat; 1774 1894 } 1775 1895 1776 1896 jsoff_t vstr(struct js *js, jsval_t value, jsoff_t *len) { 1777 1897 jsoff_t off = (jsoff_t) vdata(value); 1778 - if (len) *len = offtolen(loadoff(js, off)); 1898 + jsoff_t header = loadoff(js, off); 1899 + 1900 + if (header & ROPE_FLAG) { 1901 + jsval_t flat = rope_flatten(js, value); 1902 + if (is_err(flat)) { 1903 + if (len) *len = 0; 1904 + return 0; 1905 + } 1906 + off = (jsoff_t) vdata(flat); 1907 + header = loadoff(js, off); 1908 + } 1909 + 1910 + if (len) *len = offtolen(header); 1779 1911 return (jsoff_t) (off + sizeof(off)); 1780 1912 } 1781 1913 ··· 2165 2297 return mkentity(js, (jsoff_t) ((n << 3) | T_STR), ptr, n); 2166 2298 } 2167 2299 2300 + static jsval_t js_mkrope(struct js *js, jsval_t left, jsval_t right, jsoff_t total_len, uint8_t depth) { 2301 + jsoff_t ofs = js_alloc(js, sizeof(rope_node_t)); 2302 + if (ofs == (jsoff_t) ~0) return js_mkerr(js, "oom"); 2303 + 2304 + jsoff_t header = ((total_len + 1) << 3) | T_STR | ROPE_FLAG | ((jsoff_t)depth << ROPE_DEPTH_SHIFT); 2305 + jsval_t undef = js_mkundef(); 2306 + 2307 + memcpy(&js->mem[ofs + offsetof(rope_node_t, header)], &header, sizeof(header)); 2308 + memcpy(&js->mem[ofs + offsetof(rope_node_t, left)], &left, sizeof(left)); 2309 + memcpy(&js->mem[ofs + offsetof(rope_node_t, right)], &right, sizeof(right)); 2310 + memcpy(&js->mem[ofs + offsetof(rope_node_t, cached)], &undef, sizeof(undef)); 2311 + 2312 + return mkval(T_STR, ofs); 2313 + } 2314 + 2168 2315 jsval_t js_mkbigint(struct js *js, const char *digits, size_t len, bool negative) { 2169 2316 size_t total = len + 2; 2170 2317 jsoff_t ofs = js_alloc(js, total + sizeof(jsoff_t)); ··· 2762 2909 } 2763 2910 2764 2911 static jsval_t mkprop(struct js *js, jsval_t obj, jsval_t k, jsval_t v, jsoff_t flags) { 2765 - jsoff_t koff = (jsoff_t) vdata(k); 2912 + jsoff_t klen; jsoff_t koff = vstr(js, k, &klen); 2913 + jsoff_t koff_entity = koff - sizeof(jsoff_t); 2766 2914 jsoff_t head = (jsoff_t) vdata(obj); 2767 - char buf[sizeof(koff) + sizeof(v)]; 2915 + char buf[sizeof(koff_entity) + sizeof(v)]; 2768 2916 2769 2917 jsoff_t header = loadoff(js, head); 2770 2918 jsoff_t first_prop = header & ~(3U | FLAGMASK); 2771 2919 jsoff_t tail = loadoff(js, head + sizeof(jsoff_t) + sizeof(jsoff_t)); 2772 2920 2773 - memcpy(buf, &koff, sizeof(koff)); 2774 - memcpy(buf + sizeof(koff), &v, sizeof(v)); 2921 + memcpy(buf, &koff_entity, sizeof(koff_entity)); 2922 + memcpy(buf + sizeof(koff_entity), &v, sizeof(v)); 2775 2923 2776 - jsoff_t klen = (loadoff(js, koff) >> 3) - 1; 2777 - const char *p = (char *) &js->mem[koff + sizeof(koff)]; 2924 + const char *p = (char *) &js->mem[koff]; 2778 2925 (void)intern_string(p, klen); 2779 2926 2780 2927 jsoff_t new_prop_off = js->brk; ··· 2795 2942 } 2796 2943 2797 2944 static inline jsval_t mkprop_fast(struct js *js, jsval_t obj, jsval_t k, jsval_t v, jsoff_t flags) { 2798 - jsoff_t koff = (jsoff_t) vdata(k); 2945 + jsoff_t klen; jsoff_t koff = vstr(js, k, &klen); 2946 + jsoff_t koff_entity = koff - sizeof(jsoff_t); 2799 2947 jsoff_t head = (jsoff_t) vdata(obj); 2800 - char buf[sizeof(koff) + sizeof(v)]; 2948 + char buf[sizeof(koff_entity) + sizeof(v)]; 2801 2949 2802 2950 jsoff_t header = loadoff(js, head); 2803 2951 jsoff_t first_prop = header & ~(3U | FLAGMASK); 2804 2952 jsoff_t tail = loadoff(js, head + sizeof(jsoff_t) + sizeof(jsoff_t)); 2805 2953 2806 - memcpy(buf, &koff, sizeof(koff)); 2807 - memcpy(buf + sizeof(koff), &v, sizeof(v)); 2954 + memcpy(buf, &koff_entity, sizeof(koff_entity)); 2955 + memcpy(buf + sizeof(koff_entity), &v, sizeof(v)); 2808 2956 2809 2957 jsoff_t new_prop_off = js->brk; 2810 2958 jsval_t prop = mkentity(js, 0 | T_PROP | flags, buf, sizeof(buf)); ··· 3018 3166 } 3019 3167 3020 3168 jsval_t js_setprop(struct js *js, jsval_t obj, jsval_t k, jsval_t v) { 3021 - jsoff_t koff = (jsoff_t) vdata(k); 3022 - jsoff_t klen = offtolen(loadoff(js, koff)); 3023 - const char *key = (char *) &js->mem[koff + sizeof(jsoff_t)]; 3169 + jsoff_t klen; jsoff_t koff = vstr(js, k, &klen); 3170 + const char *key = (char *) &js->mem[koff]; 3024 3171 3025 3172 if (vtype(obj) == T_ARR && streq(key, klen, "length", 6)) { 3026 3173 jsval_t err = validate_array_length(js, v); ··· 5241 5388 return result; 5242 5389 } 5243 5390 5391 + static inline jsoff_t str_len_fast(struct js *js, jsval_t str) { 5392 + if (vtype(str) != T_STR) return 0; 5393 + jsoff_t off = (jsoff_t) vdata(str); 5394 + jsoff_t header = loadoff(js, off); 5395 + if (header & ROPE_FLAG) { 5396 + return offtolen(header & ~(ROPE_FLAG | (ROPE_DEPTH_MASK << ROPE_DEPTH_SHIFT))); 5397 + } 5398 + return offtolen(header); 5399 + } 5400 + 5244 5401 static jsval_t do_string_op(struct js *js, uint8_t op, jsval_t l, jsval_t r) { 5245 - jsoff_t n1, off1 = vstr(js, l, &n1); 5246 - jsoff_t n2, off2 = vstr(js, r, &n2); 5247 - 5248 5402 if (op == TOK_PLUS) { 5249 - string_builder_t sb; 5250 - char static_buffer[512]; 5251 - string_builder_init(&sb, static_buffer, sizeof(static_buffer)); 5403 + jsoff_t n1 = str_len_fast(js, l); 5404 + jsoff_t n2 = str_len_fast(js, r); 5405 + jsoff_t total_len = n1 + n2; 5252 5406 5253 - if (!string_builder_append(&sb, (char *)&js->mem[off1], n1) || 5254 - !string_builder_append(&sb, (char *)&js->mem[off2], n2)) { 5255 - return js_mkerr(js, "string concatenation failed"); 5407 + if (n2 == 0) return l; 5408 + if (n1 == 0) return r; 5409 + 5410 + uint8_t left_depth = (vtype(l) == T_STR && is_rope(js, l)) ? rope_depth(js, l) : 0; 5411 + uint8_t right_depth = (vtype(r) == T_STR && is_rope(js, r)) ? rope_depth(js, r) : 0; 5412 + uint8_t new_depth = (left_depth > right_depth ? left_depth : right_depth) + 1; 5413 + 5414 + if (new_depth >= ROPE_MAX_DEPTH || total_len >= ROPE_FLATTEN_THRESHOLD) { 5415 + jsval_t flat_l = l, flat_r = r; 5416 + if (is_rope(js, l)) flat_l = rope_flatten(js, l); 5417 + if (is_err(flat_l)) return flat_l; 5418 + if (is_rope(js, r)) flat_r = rope_flatten(js, r); 5419 + if (is_err(flat_r)) return flat_r; 5420 + 5421 + jsoff_t off1, off2, len1, len2; 5422 + off1 = vstr(js, flat_l, &len1); 5423 + off2 = vstr(js, flat_r, &len2); 5424 + 5425 + string_builder_t sb; 5426 + char static_buffer[512]; 5427 + string_builder_init(&sb, static_buffer, sizeof(static_buffer)); 5428 + 5429 + if ( 5430 + !string_builder_append(&sb, (char *)&js->mem[off1], len1) || 5431 + !string_builder_append(&sb, (char *)&js->mem[off2], len2) 5432 + ) return js_mkerr(js, "string concatenation failed"); 5433 + 5434 + return string_builder_finalize(js, &sb); 5256 5435 } 5257 5436 5258 - return string_builder_finalize(js, &sb); 5259 - } else if (op == TOK_EQ) { 5437 + return js_mkrope(js, l, r, total_len, new_depth); 5438 + } 5439 + 5440 + jsoff_t n1, off1 = vstr(js, l, &n1); 5441 + jsoff_t n2, off2 = vstr(js, r, &n2); 5442 + 5443 + if (op == TOK_EQ) { 5260 5444 bool eq = n1 == n2 && memcmp(&js->mem[off1], &js->mem[off2], n1) == 0; 5261 5445 return mkval(T_BOOL, eq ? 1 : 0); 5262 5446 } else if (op == TOK_NE) { ··· 5269 5453 if (cmp == 0) { 5270 5454 if (n1 == n2) { 5271 5455 return mkval(T_BOOL, (op == TOK_LE || op == TOK_GE) ? 1 : 0); 5272 - } else { 5273 - cmp = (n1 < n2) ? -1 : 1; 5274 - } 5456 + } else cmp = (n1 < n2) ? -1 : 1; 5275 5457 } 5276 5458 5277 5459 switch (op) { ··· 5281 5463 case TOK_GE: return mkval(T_BOOL, cmp >= 0 ? 1 : 0); 5282 5464 default: return js_mkerr(js, "bad str op"); 5283 5465 } 5284 - } else { 5285 - return js_mkerr(js, "bad str op"); 5286 - } 5466 + } else return js_mkerr(js, "bad str op"); 5287 5467 } 5288 5468 5289 5469 static jsval_t do_bracket_op(struct js *js, jsval_t l, jsval_t r) { ··· 5349 5529 if (endptr == temp || *endptr != '\0') idx_d = JS_NAN; 5350 5530 } 5351 5531 if (!isnan(idx_d) && idx_d >= 0 && idx_d == (double)(long)idx_d) { 5352 - jsoff_t idx = (jsoff_t) idx_d; 5353 - jsoff_t byte_len = offtolen(loadoff(js, (jsoff_t) vdata(obj))); 5354 - jsoff_t str_off = (jsoff_t) vdata(obj) + sizeof(jsoff_t); 5532 + jsoff_t idx = (jsoff_t) idx_d; jsoff_t byte_len; 5533 + jsoff_t str_off = vstr(js, obj, &byte_len); 5355 5534 const char *str_data = (const char *)&js->mem[str_off]; 5356 5535 size_t char_bytes; 5357 5536 int byte_offset = utf16_index_to_byte_offset(str_data, byte_len, idx, &char_bytes); ··· 18193 18372 long idx_l = (long) idx_d; 18194 18373 if (idx_l < 0) return tov(JS_NAN); 18195 18374 18196 - jsoff_t byte_len = offtolen(loadoff(js, (jsoff_t) vdata(str))); 18197 - jsoff_t str_off = (jsoff_t) vdata(str) + sizeof(jsoff_t); 18375 + jsoff_t byte_len; jsoff_t str_off = vstr(js, str, &byte_len); 18198 18376 const char *str_data = (const char *)&js->mem[str_off]; 18199 18377 18200 18378 uint32_t code_unit = utf16_code_unit_at(str_data, byte_len, idx_l); ··· 18214 18392 long idx_l = (long) idx_d; 18215 18393 if (idx_l < 0) return js_mkundef(); 18216 18394 18217 - jsoff_t byte_len = offtolen(loadoff(js, (jsoff_t) vdata(str))); 18218 - jsoff_t str_off = (jsoff_t) vdata(str) + sizeof(jsoff_t); 18395 + jsoff_t byte_len; 18396 + jsoff_t str_off = vstr(js, str, &byte_len); 18219 18397 const char *str_data = (const char *)&js->mem[str_off]; 18220 18398 18221 18399 uint32_t cp = utf16_codepoint_at(str_data, byte_len, idx_l); ··· 18350 18528 const char *pad_str = " "; 18351 18529 jsoff_t pad_len = 1; 18352 18530 if (nargs >= 2 && vtype(args[1]) == T_STR) { 18353 - pad_len = vstr(js, args[1], &pad_len); 18354 - pad_str = (char *) &js->mem[pad_len]; 18355 - pad_len = offtolen(loadoff(js, (jsoff_t) vdata(args[1]))); 18531 + jsoff_t pad_off = vstr(js, args[1], &pad_len); 18532 + pad_str = (char *) &js->mem[pad_off]; 18356 18533 } 18357 18534 18358 18535 if (pad_len == 0) return str; ··· 18389 18566 const char *pad_str = " "; 18390 18567 jsoff_t pad_len = 1; 18391 18568 if (nargs >= 2 && vtype(args[1]) == T_STR) { 18392 - pad_len = vstr(js, args[1], &pad_len); 18393 - pad_str = (char *) &js->mem[pad_len]; 18394 - pad_len = offtolen(loadoff(js, (jsoff_t) vdata(args[1]))); 18569 + jsoff_t pad_off = vstr(js, args[1], &pad_len); 18570 + pad_str = (char *) &js->mem[pad_off]; 18395 18571 } 18396 18572 18397 18573 if (pad_len == 0) return str; ··· 18424 18600 if (idx_d < 0 || isinf(idx_d)) return js_mkstr(js, "", 0); 18425 18601 18426 18602 jsoff_t idx = (jsoff_t) idx_d; 18427 - jsoff_t byte_len = offtolen(loadoff(js, (jsoff_t) vdata(str))); 18428 - jsoff_t str_off = (jsoff_t) vdata(str) + sizeof(jsoff_t); 18603 + jsoff_t byte_len; 18604 + jsoff_t str_off = vstr(js, str, &byte_len); 18429 18605 const char *str_data = (const char *)&js->mem[str_off]; 18430 18606 18431 18607 size_t char_bytes; ··· 18442 18618 double idx_d = nargs < 1 ? 0.0 : js_to_number(js, args[0]); 18443 18619 if (isnan(idx_d) || isinf(idx_d)) return js_mkundef(); 18444 18620 18445 - jsoff_t byte_len = offtolen(loadoff(js, (jsoff_t) vdata(str))); 18446 - jsoff_t str_off = (jsoff_t) vdata(str) + sizeof(jsoff_t); 18621 + jsoff_t byte_len; jsoff_t str_off = vstr(js, str, &byte_len); 18447 18622 const char *str_data = (const char *)&js->mem[str_off]; 18448 18623 size_t utf16_len = utf16_strlen(str_data, byte_len); 18449 18624
+22 -1
src/gc.c
··· 254 254 jsoff_t header = gc_loadoff(ctx->js->mem, old_off); 255 255 if ((header & 3) != T_STR) return old_off; 256 256 257 - jsoff_t size = esize(header); 257 + bool is_rope_str = (header & ROPE_FLAG) != 0; 258 + jsoff_t size; 259 + 260 + if (is_rope_str) { 261 + size = sizeof(rope_node_t); 262 + } else size = esize(header); 263 + 258 264 if (size == (jsoff_t)~0) return old_off; 259 265 260 266 new_off = gc_alloc(ctx, size); ··· 263 269 memcpy(&ctx->new_mem[new_off], &ctx->js->mem[old_off], size); 264 270 if (!fwd_add(&ctx->fwd, old_off, new_off)) ctx->failed = true; 265 271 mark_set(ctx, old_off); 272 + 273 + if (is_rope_str) { 274 + jsval_t left, right, cached; 275 + memcpy(&left, &ctx->js->mem[old_off + offsetof(rope_node_t, left)], sizeof(jsval_t)); 276 + memcpy(&right, &ctx->js->mem[old_off + offsetof(rope_node_t, right)], sizeof(jsval_t)); 277 + memcpy(&cached, &ctx->js->mem[old_off + offsetof(rope_node_t, cached)], sizeof(jsval_t)); 278 + 279 + jsval_t new_left = gc_update_val(ctx, left); 280 + jsval_t new_right = gc_update_val(ctx, right); 281 + jsval_t new_cached = gc_update_val(ctx, cached); 282 + 283 + memcpy(&ctx->new_mem[new_off + offsetof(rope_node_t, left)], &new_left, sizeof(jsval_t)); 284 + memcpy(&ctx->new_mem[new_off + offsetof(rope_node_t, right)], &new_right, sizeof(jsval_t)); 285 + memcpy(&ctx->new_mem[new_off + offsetof(rope_node_t, cached)], &new_cached, sizeof(jsval_t)); 286 + } 266 287 267 288 return new_off; 268 289 }